From 6328c0e163abfce679b1beffb166f72900bf0a22 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 22 Jun 2005 10:25:13 +0300 Subject: [PATCH] I2C: Coding style cleanups to via686a On Wednesday 22 June 2005 08:17, Greg KH wrote: > [PATCH] I2C: Coding style cleanups to via686a > > The via686a hardware monitoring driver has infamous coding style at the > moment. I'd like to clean up the mess before I start working on other > changes to this driver. Is the following patch acceptable? No code > change, only coding style (indentation, alignments, trailing white > space, a few parentheses and a typo). > > Signed-off-by: Jean Delvare > Signed-off-by: Greg Kroah-Hartman Nice. You missed some. This one is on top of your patch: Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/via686a.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 137d9b7cacd..164d4794839 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -1,9 +1,9 @@ /* via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring + for hardware monitoring Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , + Kyösti Mälkki , Mark Studebaker , and Bob Dougherty (Some conversion-factor data were contributed by Jonathan Teh Soon Yew @@ -171,18 +171,18 @@ static inline u8 FAN_TO_REG(long rpm, int div) /******** TEMP CONVERSIONS (Bob Dougherty) *********/ /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) if(temp<169) - return double(temp)*0.427-32.08; + return double(temp)*0.427-32.08; else if(temp>=169 && temp<=202) - return double(temp)*0.582-58.16; + return double(temp)*0.582-58.16; else - return double(temp)*0.924-127.33; + return double(temp)*0.924-127.33; A fifth-order polynomial fits the unofficial data (provided by Alex van Kaam ) a bit better. It also give more reasonable numbers on my machine (ie. they agree with what my BIOS tells me). Here's the fifth-order fit to the 8-bit data: temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. (2000-10-25- RFD: thanks to Uwe Andersen for finding my typos in this formula!) -- cgit v1.2.3 From 65fc50e50ff9f8b82c3756eccd7e7db6a267ffe9 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:13:00 -0700 Subject: [PATCH] I2C: minor TPS6501x cleanups This includes various small cleanups and fixes to the TPS 6501x driver that came mostly from review feedback by Jean Delvare; thanks Jean! Also some goofy whitespace gets fixed. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 1 - drivers/i2c/chips/tps65010.c | 59 +++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a0982da0980..b28964b0800 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -509,7 +509,6 @@ config TPS65010 This driver can also be built as a module. If so, the module will be called tps65010. - config SENSORS_M41T00 tristate "ST M41T00 RTC chip" depends on I2C && PPC32 diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index c0ac01b6003..280e9638c0f 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -18,7 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef DEBUG #include #include @@ -49,11 +48,7 @@ MODULE_DESCRIPTION("TPS6501x Power Management Driver"); MODULE_LICENSE("GPL"); -/* only two addresses possible */ -#define TPS_BASE 0x48 -static unsigned short normal_i2c[] = { - TPS_BASE, - I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -102,7 +97,7 @@ struct tps65010 { u8 chgstatus, regstatus, chgconf; u8 nmask1, nmask2; - /* plus four GPIOs, probably used to switch power */ + /* not currently tracking GPIO state */ }; #define POWER_POLL_DELAY msecs_to_jiffies(800) @@ -135,7 +130,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus) (regstatus & TPS_REG_COVER) ? " uncover" : "", (regstatus & TPS_REG_UVLO) ? " UVLO" : "", (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", - (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "", (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); @@ -143,7 +138,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus) static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) { - char *hibit; + const char *hibit; if (por) hibit = (chgconfig & TPS_CHARGE_POR) @@ -295,7 +290,7 @@ static int dbg_show(struct seq_file *s, void *_) seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); for (i = 0; i < 4; i++) { - if (value & (1 << (4 +i))) + if (value & (1 << (4 + i))) seq_printf(s, " gpio%d-out %s\n", i + 1, (value & (1 << i)) ? "low" : "hi "); else @@ -481,7 +476,7 @@ static int __exit tps65010_detach_client(struct i2c_client *client) debugfs_remove(tps->file); if (i2c_detach_client(client) == 0) kfree(tps); - the_tps = 0; + the_tps = NULL; return 0; } @@ -514,7 +509,6 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) INIT_WORK(&tps->work, tps65010_work, tps); tps->irq = -1; tps->client.addr = address; - i2c_set_clientdata(&tps->client, tps); tps->client.adapter = bus; tps->client.driver = &tps65010_driver; strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); @@ -523,9 +517,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) if (status < 0) { dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", DRIVER_NAME, address, status); -fail1: - kfree(tps); - return 0; + goto fail1; } #ifdef CONFIG_ARM @@ -535,7 +527,7 @@ fail1: tps->irq = OMAP_GPIO_IRQ(58); omap_request_gpio(58); omap_set_gpio_direction(58, 1); - omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); + set_irq_type(tps->irq, IRQT_FALLING); } if (machine_is_omap_osk()) { tps->model = TPS65010; @@ -543,7 +535,7 @@ fail1: tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); omap_request_gpio(OMAP_MPUIO(1)); omap_set_gpio_direction(OMAP_MPUIO(1), 1); - omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); + set_irq_type(tps->irq, IRQT_FALLING); } if (machine_is_omap_h3()) { tps->model = TPS65013; @@ -633,6 +625,9 @@ fail1: tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, tps, DEBUG_FOPS); return 0; +fail1: + kfree(tps); + return 0; } static int __init tps65010_scan_bus(struct i2c_adapter *bus) @@ -645,7 +640,6 @@ static int __init tps65010_scan_bus(struct i2c_adapter *bus) static struct i2c_driver tps65010_driver = { .owner = THIS_MODULE, .name = "tps65010", - .id = 888, /* FIXME assign "official" value */ .flags = I2C_DF_NOTIFY, .attach_adapter = tps65010_scan_bus, .detach_client = __exit_p(tps65010_detach_client), @@ -744,7 +738,7 @@ int tps65010_set_led(unsigned led, unsigned mode) if (!the_tps) return -ENODEV; - if(led == LED1) + if (led == LED1) offs = 0; else { offs = 2; @@ -753,11 +747,13 @@ int tps65010_set_led(unsigned led, unsigned mode) down(&the_tps->lock); - dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_ON + offs)); - dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_PER + offs)); switch (mode) { case OFF: @@ -773,7 +769,7 @@ int tps65010_set_led(unsigned led, unsigned mode) led_per = 0x08 | (1 << 7); break; default: - printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", + printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n", DRIVER_NAME); up(&the_tps->lock); return -EINVAL; @@ -789,7 +785,7 @@ int tps65010_set_led(unsigned led, unsigned mode) return status; } - dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); status = i2c_smbus_write_byte_data(&the_tps->client, @@ -802,8 +798,9 @@ int tps65010_set_led(unsigned led, unsigned mode) return status; } - dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_PER + offs)); up(&the_tps->lock); @@ -874,7 +871,7 @@ int tps65010_set_low_pwr(unsigned mode) if (status != 0) printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); + DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); @@ -900,14 +897,14 @@ int tps65010_config_vregs1(unsigned value) down(&the_tps->lock); pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); status = i2c_smbus_write_byte_data(&the_tps->client, TPS_VREGS1, value); if (status != 0) printk(KERN_ERR "%s: Failed to write vregs1 register\n", - DRIVER_NAME); + DRIVER_NAME); else pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); @@ -1009,7 +1006,7 @@ static int __init tps_init(void) msleep(10); } -#if defined(CONFIG_ARM) +#ifdef CONFIG_ARM if (machine_is_omap_osk()) { // FIXME: More should be placed in the initialization code -- cgit v1.2.3 From 541e6a02768404efb06bd1ea5f33d614732f41fc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 22:18:08 +0200 Subject: [PATCH] I2C: Strip trailing whitespace from strings Here is a simple patch originally from Denis Vlasenko, which strips a useless trailing whitespace from 8 strings in 4 i2c drivers. Please apply, thanks. From: Denis Vlasenko Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/algos/i2c-algo-ite.c | 8 ++++---- drivers/i2c/busses/i2c-i801.c | 4 ++-- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index 68e9e6832ca..e6cae39f47a 100644 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -208,7 +208,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sdalo(adap); - printk("test_bus:1 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:1 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 != getsda(adap) ) { printk("test_bus: %s SDA stuck high!\n",name); @@ -221,7 +221,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sdahi(adap); - printk("test_bus:2 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:2 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 == getsda(adap) ) { printk("test_bus: %s SDA stuck low!\n",name); @@ -234,7 +234,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } scllo(adap); - printk("test_bus:3 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:3 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 != getscl(adap) ) { @@ -247,7 +247,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sclhi(adap); - printk("test_bus:4 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:4 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 == getscl(adap) ) { printk("test_bus: %s SCL stuck low!\n",name); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 45e6efb1dcd..0ab7e37f5b0 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -194,7 +194,7 @@ static int i801_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n", + dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { @@ -315,7 +315,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, } if (temp & errmask) { dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " - "Resetting... \n", temp); + "Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { dev_err(&I801_dev->dev, diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 1f80ba9da6f..6d34ee381ce 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -243,7 +243,7 @@ static int piix4_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " - "Resetting... \n", temp); + "Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 2b5911cfb7b..bbd5e4e52f0 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -228,7 +228,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) /* Make sure the SMBus host is ready to start transmitting */ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8); if (temp != 0x00) { - dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting... \n", temp); + dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp); sis5595_write(SMB_STS_LO, temp & 0xff); sis5595_write(SMB_STS_HI, temp >> 8); if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) { -- cgit v1.2.3 From 9ab1ee2ab7d65979c0f14a60ee1f29f8988f5811 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 24 Jun 2005 21:14:16 +0200 Subject: [PATCH] I2C: New max6875 driver may corrupt EEPROMs After a careful code analysis on the new max6875 driver (drivers/i2c/chips/max6875.c), I have come to the conclusion that this driver may cause EEPROM corruptions if used on random systems. The EEPROM part of the MAX6875 chip is accessed using rather uncommon I2C sequences. What is seen by the MAX6875 as reads can be seen by a standard EEPROM (24C02) as writes. If you check the detection method used by the driver, you'll find that the first SMBus command it will send on the bus is i2c_smbus_write_byte_data(client, 0x80, 0x40). For the MAX6875 it makes an internal pointer point to a specific offset of the EEPROM waiting for a subsequent read command, so it's not an actual data write operation, but for a standard EEPROM, this instead means writing value 0x40 to offset 0x80. Blame Philips and Intel for the obscure protocol. Since the MAX6875 and the standard, common 24C02 EEPROMs share two I2C addresses (0x50 and 0x52), loading the max6875 driver on a system with standard EEPROMs at either address will trigger a write on these EEPROMs, which will lead to their corruption if they happen not to be write protected. This kind of EEPROMs can be found on memory modules (SPD), ethernet adapters (MAC address), laptops (proprietary data) and displays (EDID/DDC). Most of these are hopefully write-protected, but not all of them. For this reason, I would recommend that the max6875 driver be neutralized, in a way that nobody can corrupt his/her EEPROMs by just loading the driver. This means either deleting the driver completely, or not listing any default address for it. I'd like this to be done before 2.6.13-rc1 is released. Additionally, the max6875 driver lacks the 24RF08 corruption preventer present in the eeprom driver, which means that loading this driver in a system with such a chip would corrupt it as well. Here is a proposed quick patch addressing the issue, although I wouldn't mind a complete removal if it makes everyone feel safer. I think Ben has plans to replace this driver by a much simplified one anyway. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index fe6b150ec4c..c4f14d9623c 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -37,7 +37,8 @@ #include /* Addresses to scan */ -static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END}; +/* No address scanned by default, as this could corrupt standard EEPROMS. */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; /* Insmod parameters */ @@ -369,6 +370,9 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) new_client->driver = &max6875_driver; new_client->flags = 0; + /* Prevent 24RF08 corruption */ + i2c_smbus_write_quick(new_client, 0); + /* Setup the user section */ data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; -- cgit v1.2.3 From 2146fec20c38d926f0d88413977f941f42a14588 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 23:41:39 +0200 Subject: [PATCH] I2C: max6875 Kconfig update Here is a proposed Kconfig update for the new max6875 i2c chip driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index b28964b0800..5bd72c480c9 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -519,13 +519,16 @@ config SENSORS_M41T00 will be called m41t00. config SENSORS_MAX6875 - tristate "MAXIM MAX6875 Power supply supervisor" + tristate "Maxim MAX6875 Power supply supervisor" depends on I2C && EXPERIMENTAL help - If you say yes here you get support for the MAX6875 - EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors. + If you say yes here you get support for the Maxim MAX6875 + EEPROM-programmable, quad power-supply sequencer/supervisor. - This provides a interface to program the EEPROM and reset the chip. + This provides an interface to program the EEPROM and reset the chip. + + This driver also supports the Maxim MAX6874 hex power-supply + sequencer/supervisor if found at a compatible address. This driver can also be built as a module. If so, the module will be called max6875. -- cgit v1.2.3 From 5da69ba42aa42a479c0f5d8cb8351ebb6b51c12e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 1 Jul 2005 14:28:15 +0200 Subject: [PATCH] I2C: m41t00: fix incorrect kfree Here is a simple path fixing an incorrect kfree in the m41t00 i2c chip driver. The current code happens to work by accident, but the freed pointer isn't the one which was allocated in the first place, which could cause problems later. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/m41t00.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 5e463c47bfb..778d7e12859 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -207,7 +207,7 @@ m41t00_detach(struct i2c_client *client) int rc; if ((rc = i2c_detach_client(client)) == 0) { - kfree(i2c_get_clientdata(client)); + kfree(client); tasklet_kill(&m41t00_tasklet); } return rc; -- cgit v1.2.3 From a0920e10438e9fe8b22aba607083347c84458ed8 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Tue, 28 Jun 2005 00:21:30 -0400 Subject: [PATCH] i2c: make better use of IDR in i2c-core This patch uses the already existing IDR mechanism to simplify and improve the i2c_get_adapter function in i2c-core. Signed-off-by: Mark M. Hoffman Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 51ce268998c..4fd4f52c8e9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -156,7 +156,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) goto out_unlock; } - res = idr_get_new(&i2c_adapter_idr, NULL, &id); + res = idr_get_new(&i2c_adapter_idr, adap, &id); if (res < 0) { if (res == -EAGAIN) res = -ENOMEM; @@ -765,20 +765,15 @@ int i2c_adapter_id(struct i2c_adapter *adap) struct i2c_adapter* i2c_get_adapter(int id) { - struct list_head *item; struct i2c_adapter *adapter; down(&core_lists); - list_for_each(item,&adapters) { - adapter = list_entry(item, struct i2c_adapter, list); - if (id == adapter->nr && - try_module_get(adapter->owner)) { - up(&core_lists); - return adapter; - } - } + adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + if (adapter && !try_module_get(adapter->owner)) + adapter = NULL; + up(&core_lists); - return NULL; + return adapter; } void i2c_put_adapter(struct i2c_adapter *adap) -- cgit v1.2.3 From 2db32767874fe53faff4f80de878ca19927efc1f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 23:43:00 +0200 Subject: [PATCH] I2C: drop bogus eeprom comment This simple patch drops an out-of-date comment in the eeprom i2c chip driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/eeprom.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index addf0adc24d..6ea413f6d5e 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -173,9 +173,6 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_BYTE)) goto exit; - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access eeprom_{read,write}_value. */ if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; -- cgit v1.2.3 From 80efa8c72006a1c04004f8fb07b22073348e4bf2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 1 Jul 2005 00:17:27 +0200 Subject: [PATCH] I2C: SENSORS_ATXP1 must select I2C_SENSOR On Thu, Jun 30, 2005 at 11:47:09PM +0200, Sebastian Pigulak wrote: > I've tried patching linux-2.6.13-RC1 with patch-2.6.13-rc1-git2 and > building atxp1(it allows Vcore voltage changing) into the kernel. > Unfortunately, the kernel compilation stops with: > > LD init/built-in.o > LD vmlinux > drivers/built-in.o(.text+0x92298): In function `atxp1_detect': > : undefined reference to `i2c_which_vrm' > drivers/built-in.o(.text+0x921ae): In function `atxp1_attach_adapter': > : undefined reference to `i2c_detect' > make: *** [vmlinux] B??d 1 > ==> ERROR: Build Failed. Aborting... > > Could someone have a look at the module and possibly fix it up? SENSORS_ATXP1 must select I2C_SENSOR. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 5bd72c480c9..fddfc11b297 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -80,6 +80,7 @@ config SENSORS_ASB100 config SENSORS_ATXP1 tristate "Attansic ATXP1 VID controller" depends on I2C && EXPERIMENTAL + select I2C_SENSOR help If you say yes here you get support for the Attansic ATXP1 VID controller. -- cgit v1.2.3 From 0e65f82814e9828d3ff54988de9e7c0b36794daa Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 30 Jun 2005 22:52:38 +0400 Subject: [PATCH] w1: fix CRC calculation on bigendian platforms. In the 2.6.13-rc1 code the "rn" structure is in the wrong-endianness when passed to w1_attach_slave_device(). This causes problems like the family and crc being swapped around. Signed-off-by: Roger Blofeld Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 312cf3220f1..8a9c4282250 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -516,6 +516,7 @@ static void w1_slave_found(unsigned long data, u64 rn) struct w1_reg_num *tmp; int family_found = 0; struct w1_master *dev; + u64 rn_le = cpu_to_le64(rn); dev = w1_search_master(data); if (!dev) { @@ -544,10 +545,8 @@ static void w1_slave_found(unsigned long data, u64 rn) slave_count++; } - rn = cpu_to_le64(rn); - if (slave_count == dev->slave_count && - rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) { + rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) { w1_attach_slave_device(dev, tmp); } -- cgit v1.2.3 From ad2f931dcb41bcfae38cc77d78b7821dfef83cf2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Jul 2005 18:15:49 +0200 Subject: [PATCH] I2C: Move hwmon drivers (1/3) Part 1: Configuration files and Makefiles. From: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/hwmon/Kconfig | 420 +++++++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/Makefile | 44 +++++ drivers/i2c/chips/Kconfig | 402 +------------------------------------------ drivers/i2c/chips/Makefile | 38 +--- 6 files changed, 470 insertions(+), 437 deletions(-) create mode 100644 drivers/hwmon/Kconfig create mode 100644 drivers/hwmon/Makefile (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index aed4a9b97c1..cf087de3b3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -44,6 +44,8 @@ source "drivers/i2c/Kconfig" source "drivers/w1/Kconfig" +source "drivers/hwmon/Kconfig" + source "drivers/misc/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 3167be54fed..126a851d565 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ +obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig new file mode 100644 index 00000000000..140d5f851a5 --- /dev/null +++ b/drivers/hwmon/Kconfig @@ -0,0 +1,420 @@ +# +# I2C Sensor chip drivers configuration +# + +menu "Hardware Monitoring support" + +config HWMON + tristate "Hardware Monitoring support" + default y + help + Hardware monitoring devices let you monitor the hardware health + of a system. Most modern motherboards include such a device. It + can include temperature sensors, voltage sensors, fan speed + sensors and various additional features such as the ability to + control the speed of the fans. + +config SENSORS_ADM1021 + tristate "Analog Devices ADM1021 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1021 + and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, + Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, + and the XEON processor built-in sensor. + + This driver can also be built as a module. If so, the module + will be called adm1021. + +config SENSORS_ADM1025 + tristate "Analog Devices ADM1025 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1025 + and Philips NE1619 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm1025. + +config SENSORS_ADM1026 + tristate "Analog Devices ADM1026 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1026 + sensor chip. + + This driver can also be built as a module. If so, the module + will be called adm1026. + +config SENSORS_ADM1031 + tristate "Analog Devices ADM1031 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1031 + and ADM1030 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm1031. + +config SENSORS_ADM9240 + tristate "Analog Devices ADM9240 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM9240, + Dallas DS1780, National Semiconductor LM81 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm9240. + +config SENSORS_ASB100 + tristate "Asus ASB100 Bach" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the ASB100 Bach sensor + chip found on some Asus mainboards. + + This driver can also be built as a module. If so, the module + will be called asb100. + +config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the Attansic ATXP1 VID + controller. + + If your board have such a chip, you are able to control your CPU + core and other voltages. + + This driver can also be built as a module. If so, the module + will be called atxp1. + +config SENSORS_DS1621 + tristate "Dallas Semiconductor DS1621 and DS1625" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Dallas Semiconductor + DS1621 and DS1625 sensor chips. + + This driver can also be built as a module. If so, the module + will be called ds1621. + +config SENSORS_FSCHER + tristate "FSC Hermes" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Fujitsu Siemens + Computers Hermes sensor chips. + + 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 HWMON && 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 HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for Genesys Logic GL518SM + sensor chips. + + This driver can also be built as a module. If so, the module + will be called gl518sm. + +config SENSORS_GL520SM + tristate "Genesys Logic GL520SM" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Genesys Logic GL520SM + sensor chips. + + This driver can also be built as a module. If so, the module + will be called gl520sm. + +config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for ITE IT87xx sensor chips + and clones: SiS960. + + This driver can also be built as a module. If so, the module + will be called it87. + +config SENSORS_LM63 + tristate "National Semiconductor LM63" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the National Semiconductor + LM63 remote diode digital temperature sensor with integrated fan + control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) + motherboard, among others. + + This driver can also be built as a module. If so, the module + will be called lm63. + +config SENSORS_LM75 + tristate "National Semiconductor LM75 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM75 + sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in + 9-bit precision mode), and TelCom (now Microchip) TCN75. + + The DS75 and DS1775 in 10- to 12-bit precision modes will require + a force module parameter. The driver will not handle the extra + precision anyhow. + + This driver can also be built as a module. If so, the module + will be called lm75. + +config SENSORS_LM77 + tristate "National Semiconductor LM77" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM77 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm77. + +config SENSORS_LM78 + tristate "National Semiconductor LM78 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM78, + LM78-J and LM79. + + This driver can also be built as a module. If so, the module + will be called lm78. + +config SENSORS_LM80 + tristate "National Semiconductor LM80" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor + LM80 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm80. + +config SENSORS_LM83 + tristate "National Semiconductor LM83" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor + LM83 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm83. + +config SENSORS_LM85 + tristate "National Semiconductor LM85 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM85 + sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. + + This driver can also be built as a module. If so, the module + will be called lm85. + +config SENSORS_LM87 + tristate "National Semiconductor LM87" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM87 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm87. + +config SENSORS_LM90 + tristate "National Semiconductor LM90 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM90, + LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and + MAX6658 sensor chips. + + The Analog Devices ADT7461 sensor chip is also supported, but only + if found in ADM1032 compatibility mode. + + This driver can also be built as a module. If so, the module + will be called lm90. + +config SENSORS_LM92 + tristate "National Semiconductor LM92 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM92 + and Maxim MAX6635 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm92. + +config SENSORS_MAX1619 + tristate "Maxim MAX1619 sensor chip" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for MAX1619 sensor chip. + + This driver can also be built as a module. If so, the module + will be called max1619. + +config SENSORS_PC87360 + tristate "National Semiconductor PC87360 family" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get access to the hardware monitoring + functions of the National Semiconductor PC8736x Super-I/O chips. + The PC87360, PC87363 and PC87364 only have fan monitoring and + control. The PC87365 and PC87366 additionally have voltage and + temperature monitoring. + + This driver can also be built as a module. If so, the module + will be called pc87360. + +config SENSORS_SIS5595 + tristate "Silicon Integrated Systems Corp. SiS5595" + depends on HWMON && I2C && PCI && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated sensors in + SiS5595 South Bridges. + + This driver can also be built as a module. If so, the module + will be called sis5595. + +config SENSORS_SMSC47M1 + tristate "SMSC LPC47M10x and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated fan + monitoring and control capabilities of the SMSC LPC47B27x, + LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. + + This driver can also be built as a module. If so, the module + will be called smsc47m1. + +config SENSORS_SMSC47B397 + tristate "SMSC LPC47B397-NC" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the SMSC LPC47B397-NC + sensor chip. + + This driver can also be built as a module. If so, the module + will be called smsc47b397. + +config SENSORS_VIA686A + tristate "VIA686A" + depends on HWMON && I2C && PCI + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated sensors in + Via 686A/B South Bridges. + + This driver can also be built as a module. If so, the module + will be called via686a. + +config SENSORS_W83781D + tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for the Winbond W8378x series + of sensor chips: the W83781D, W83782D, W83783S and W83627HF, + and the similar Asus AS99127F. + + This driver can also be built as a module. If so, the module + will be called w83781d. + +config SENSORS_W83L785TS + tristate "Winbond W83L785TS-S" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the Winbond W83L785TS-S + sensor chip, which is used on the Asus A7N8X, among other + motherboards. + + This driver can also be built as a module. If so, the module + will be called w83l785ts. + +config SENSORS_W83627HF + tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the Winbond W836X7 series + of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF + + This driver can also be built as a module. If so, the module + will be called w83627hf. + +config SENSORS_W83627EHF + tristate "Winbond W83627EHF" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get preliminary support for the hardware + monitoring functionality of the Winbond W83627EHF Super-I/O chip. + Only fan and temperature inputs are supported at the moment, while + the chip does much more than that. + + This driver can also be built as a module. If so, the module + will be called w83627ehf. + +config HWMON_DEBUG_CHIP + bool "Hardware Monitoring Chip debugging messages" + depends on HWMON + default n + help + Say Y here if you want the I2C chip drivers to produce a bunch of + debug messages to the system log. Select this if you are having + a problem with I2C support and want to see more of what is going + on. + +endmenu diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile new file mode 100644 index 00000000000..2781403a023 --- /dev/null +++ b/drivers/hwmon/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for sensor chip drivers. +# + +# asb100, then w83781d go first, as they can override other drivers' addresses. +obj-$(CONFIG_SENSORS_ASB100) += asb100.o +obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o +obj-$(CONFIG_SENSORS_W83781D) += w83781d.o + +obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o +obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o +obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o +obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o +obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o +obj-$(CONFIG_SENSORS_DS1621) += ds1621.o +obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o +obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o +obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o +obj-$(CONFIG_SENSORS_IT87) += it87.o +obj-$(CONFIG_SENSORS_LM63) += lm63.o +obj-$(CONFIG_SENSORS_LM75) += lm75.o +obj-$(CONFIG_SENSORS_LM77) += lm77.o +obj-$(CONFIG_SENSORS_LM78) += lm78.o +obj-$(CONFIG_SENSORS_LM80) += lm80.o +obj-$(CONFIG_SENSORS_LM83) += lm83.o +obj-$(CONFIG_SENSORS_LM85) += lm85.o +obj-$(CONFIG_SENSORS_LM87) += lm87.o +obj-$(CONFIG_SENSORS_LM90) += lm90.o +obj-$(CONFIG_SENSORS_LM92) += lm92.o +obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_PC87360) += pc87360.o +obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o +obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o +obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o +obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o +obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + +ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) +EXTRA_CFLAGS += -DDEBUG +endif + diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index fddfc11b297..43f70dbfc03 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -1,410 +1,12 @@ # -# I2C Sensor and "other" chip configuration +# Miscellaneous I2C chip drivers configuration # -menu "Hardware Sensors Chip support" - depends on I2C - config I2C_SENSOR tristate default n -config SENSORS_ADM1021 - tristate "Analog Devices ADM1021 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1021 - and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. - - This driver can also be built as a module. If so, the module - will be called adm1021. - -config SENSORS_ADM1025 - tristate "Analog Devices ADM1025 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1025 - and Philips NE1619 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1025. - -config SENSORS_ADM1026 - tristate "Analog Devices ADM1026 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1026 - sensor chip. - - This driver can also be built as a module. If so, the module - will be called adm1026. - -config SENSORS_ADM1031 - tristate "Analog Devices ADM1031 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1031 - and ADM1030 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1031. - -config SENSORS_ADM9240 - tristate "Analog Devices ADM9240 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM9240, - Dallas DS1780, National Semiconductor LM81 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm9240. - -config SENSORS_ASB100 - tristate "Asus ASB100 Bach" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the ASB100 Bach sensor - chip found on some Asus mainboards. - - This driver can also be built as a module. If so, the module - will be called asb100. - -config SENSORS_ATXP1 - tristate "Attansic ATXP1 VID controller" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the Attansic ATXP1 VID - controller. - - If your board have such a chip, you are able to control your CPU - core and other voltages. - - This driver can also be built as a module. If so, the module - will be called atxp1. - -config SENSORS_DS1621 - tristate "Dallas Semiconductor DS1621 and DS1625" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Dallas Semiconductor - DS1621 and DS1625 sensor chips. - - This driver can also be built as a module. If so, the module - will be called ds1621. - -config SENSORS_FSCHER - tristate "FSC Hermes" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Fujitsu Siemens - Computers Hermes sensor chips. - - 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 - select I2C_SENSOR - help - If you say yes here you get support for Genesys Logic GL518SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl518sm. - -config SENSORS_GL520SM - tristate "Genesys Logic GL520SM" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Genesys Logic GL520SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl520sm. - -config SENSORS_IT87 - tristate "ITE IT87xx and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for ITE IT87xx sensor chips - and clones: SiS960. - - This driver can also be built as a module. If so, the module - will be called it87. - -config SENSORS_LM63 - tristate "National Semiconductor LM63" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the National Semiconductor - LM63 remote diode digital temperature sensor with integrated fan - control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) - motherboard, among others. - - This driver can also be built as a module. If so, the module - will be called lm63. - -config SENSORS_LM75 - tristate "National Semiconductor LM75 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM75 - sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in - 9-bit precision mode), and TelCom (now Microchip) TCN75. - - The DS75 and DS1775 in 10- to 12-bit precision modes will require - a force module parameter. The driver will not handle the extra - precision anyhow. - - This driver can also be built as a module. If so, the module - will be called lm75. - -config SENSORS_LM77 - tristate "National Semiconductor LM77" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM77 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm77. - -config SENSORS_LM78 - tristate "National Semiconductor LM78 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM78, - LM78-J and LM79. - - This driver can also be built as a module. If so, the module - will be called lm78. - -config SENSORS_LM80 - tristate "National Semiconductor LM80" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor - LM80 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm80. - -config SENSORS_LM83 - tristate "National Semiconductor LM83" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor - LM83 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm83. - -config SENSORS_LM85 - tristate "National Semiconductor LM85 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM85 - sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. - - This driver can also be built as a module. If so, the module - will be called lm85. - -config SENSORS_LM87 - tristate "National Semiconductor LM87" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM87 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm87. - -config SENSORS_LM90 - tristate "National Semiconductor LM90 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and - MAX6658 sensor chips. - - The Analog Devices ADT7461 sensor chip is also supported, but only - if found in ADM1032 compatibility mode. - - This driver can also be built as a module. If so, the module - will be called lm90. - -config SENSORS_LM92 - tristate "National Semiconductor LM92 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM92 - and Maxim MAX6635 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm92. - -config SENSORS_MAX1619 - tristate "Maxim MAX1619 sensor chip" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for MAX1619 sensor chip. - - This driver can also be built as a module. If so, the module - will be called max1619. - -config SENSORS_PC87360 - tristate "National Semiconductor PC87360 family" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC8736x Super-I/O chips. - The PC87360, PC87363 and PC87364 only have fan monitoring and - control. The PC87365 and PC87366 additionally have voltage and - temperature monitoring. - - This driver can also be built as a module. If so, the module - will be called pc87360. - -config SENSORS_SMSC47B397 - tristate "SMSC LPC47B397-NC" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the SMSC LPC47B397-NC - sensor chip. - - This driver can also be built as a module. If so, the module - will be called smsc47b397. - -config SENSORS_SIS5595 - tristate "Silicon Integrated Systems Corp. SiS5595" - depends on I2C && PCI && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated sensors in - SiS5595 South Bridges. - - This driver can also be built as a module. If so, the module - will be called sis5595. - -config SENSORS_SMSC47M1 - tristate "SMSC LPC47M10x and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated fan - monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. - - This driver can also be built as a module. If so, the module - will be called smsc47m1. - -config SENSORS_VIA686A - tristate "VIA686A" - depends on I2C && PCI - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated sensors in - Via 686A/B South Bridges. - - This driver can also be built as a module. If so, the module - will be called via686a. - -config SENSORS_W83781D - tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for the Winbond W8378x series - of sensor chips: the W83781D, W83782D, W83783S and W83627HF, - and the similar Asus AS99127F. - - This driver can also be built as a module. If so, the module - will be called w83781d. - -config SENSORS_W83L785TS - tristate "Winbond W83L785TS-S" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the Winbond W83L785TS-S - sensor chip, which is used on the Asus A7N8X, among other - motherboards. - - This driver can also be built as a module. If so, the module - will be called w83l785ts. - -config SENSORS_W83627HF - tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the Winbond W836X7 series - of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF - - This driver can also be built as a module. If so, the module - will be called w83627hf. - -config SENSORS_W83627EHF - tristate "Winbond W83627EHF" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get preliminary support for the hardware - monitoring functionality of the Winbond W83627EHF Super-I/O chip. - Only fan and temperature inputs are supported at the moment, while - the chip does much more than that. - - This driver can also be built as a module. If so, the module - will be called w83627ehf. - -endmenu - -menu "Other I2C Chip support" +menu "Miscellaneous I2C Chip support" depends on I2C config SENSORS_DS1337 diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index b5e6d2f84f9..a876dd42b86 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -1,52 +1,16 @@ # -# Makefile for sensor and "other" I2C chip drivers. +# Makefile for miscellaneous I2C chip drivers. # -# asb100, then w83781d go first, as they can override other drivers' addresses. -obj-$(CONFIG_SENSORS_ASB100) += asb100.o -obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o -obj-$(CONFIG_SENSORS_W83781D) += w83781d.o - -obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o -obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o -obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o -obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o -obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o -obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o obj-$(CONFIG_SENSORS_DS1374) += ds1374.o -obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o -obj-$(CONFIG_SENSORS_FSCHER) += fscher.o -obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o -obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o -obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o -obj-$(CONFIG_SENSORS_IT87) += it87.o -obj-$(CONFIG_SENSORS_LM63) += lm63.o -obj-$(CONFIG_SENSORS_LM75) += lm75.o -obj-$(CONFIG_SENSORS_LM77) += lm77.o -obj-$(CONFIG_SENSORS_LM78) += lm78.o -obj-$(CONFIG_SENSORS_LM80) += lm80.o -obj-$(CONFIG_SENSORS_LM83) += lm83.o -obj-$(CONFIG_SENSORS_LM85) += lm85.o -obj-$(CONFIG_SENSORS_LM87) += lm87.o -obj-$(CONFIG_SENSORS_LM90) += lm90.o -obj-$(CONFIG_SENSORS_LM92) += lm92.o -obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o -obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o -obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o -obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o -obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o -obj-$(CONFIG_SENSORS_VIA686A) += via686a.o -obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o -obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o - obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o -- cgit v1.2.3 From 8d5d45fb14680326f833295f2316a4ec5e357220 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Jul 2005 18:20:26 +0200 Subject: [PATCH] I2C: Move hwmon drivers (2/3) Part 2: Move the driver files themselves. Note that the patch "adds trailing whitespace", because it does move the files as-is, and some files happen to have trailing whitespace. From: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1021.c | 402 ++++++++++ drivers/hwmon/adm1025.c | 577 ++++++++++++++ drivers/hwmon/adm1026.c | 1714 ++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/adm1031.c | 977 +++++++++++++++++++++++ drivers/hwmon/adm9240.c | 791 ++++++++++++++++++ drivers/hwmon/asb100.c | 1065 +++++++++++++++++++++++++ drivers/hwmon/atxp1.c | 361 +++++++++ drivers/hwmon/ds1621.c | 341 ++++++++ drivers/hwmon/fscher.c | 691 ++++++++++++++++ drivers/hwmon/fscpos.c | 641 +++++++++++++++ drivers/hwmon/gl518sm.c | 604 ++++++++++++++ drivers/hwmon/gl520sm.c | 769 ++++++++++++++++++ drivers/hwmon/it87.c | 1184 +++++++++++++++++++++++++++ drivers/hwmon/lm63.c | 597 ++++++++++++++ drivers/hwmon/lm75.c | 296 +++++++ drivers/hwmon/lm75.h | 49 ++ drivers/hwmon/lm77.c | 420 ++++++++++ drivers/hwmon/lm78.c | 795 +++++++++++++++++++ drivers/hwmon/lm80.c | 601 ++++++++++++++ drivers/hwmon/lm83.c | 408 ++++++++++ drivers/hwmon/lm85.c | 1575 ++++++++++++++++++++++++++++++++++++ drivers/hwmon/lm87.c | 828 +++++++++++++++++++ drivers/hwmon/lm90.c | 655 +++++++++++++++ drivers/hwmon/lm92.c | 429 ++++++++++ drivers/hwmon/max1619.c | 372 +++++++++ drivers/hwmon/pc87360.c | 1348 +++++++++++++++++++++++++++++++ drivers/hwmon/sis5595.c | 817 +++++++++++++++++++ drivers/hwmon/smsc47b397.c | 352 +++++++++ drivers/hwmon/smsc47m1.c | 593 ++++++++++++++ drivers/hwmon/via686a.c | 875 ++++++++++++++++++++ drivers/hwmon/w83627ehf.c | 846 ++++++++++++++++++++ drivers/hwmon/w83627hf.c | 1511 +++++++++++++++++++++++++++++++++++ drivers/hwmon/w83781d.c | 1632 ++++++++++++++++++++++++++++++++++++++ drivers/hwmon/w83l785ts.c | 328 ++++++++ drivers/i2c/chips/adm1021.c | 402 ---------- drivers/i2c/chips/adm1025.c | 577 -------------- drivers/i2c/chips/adm1026.c | 1714 ---------------------------------------- drivers/i2c/chips/adm1031.c | 977 ----------------------- drivers/i2c/chips/adm9240.c | 791 ------------------ drivers/i2c/chips/asb100.c | 1065 ------------------------- drivers/i2c/chips/atxp1.c | 361 --------- drivers/i2c/chips/ds1621.c | 341 -------- drivers/i2c/chips/fscher.c | 691 ---------------- drivers/i2c/chips/fscpos.c | 641 --------------- drivers/i2c/chips/gl518sm.c | 604 -------------- drivers/i2c/chips/gl520sm.c | 769 ------------------ drivers/i2c/chips/it87.c | 1184 --------------------------- drivers/i2c/chips/lm63.c | 597 -------------- drivers/i2c/chips/lm75.c | 296 ------- drivers/i2c/chips/lm75.h | 49 -- drivers/i2c/chips/lm77.c | 420 ---------- drivers/i2c/chips/lm78.c | 795 ------------------- drivers/i2c/chips/lm80.c | 601 -------------- drivers/i2c/chips/lm83.c | 408 ---------- drivers/i2c/chips/lm85.c | 1575 ------------------------------------ drivers/i2c/chips/lm87.c | 828 ------------------- drivers/i2c/chips/lm90.c | 655 --------------- drivers/i2c/chips/lm92.c | 429 ---------- drivers/i2c/chips/max1619.c | 372 --------- drivers/i2c/chips/pc87360.c | 1348 ------------------------------- drivers/i2c/chips/sis5595.c | 817 ------------------- drivers/i2c/chips/smsc47b397.c | 352 --------- drivers/i2c/chips/smsc47m1.c | 593 -------------- drivers/i2c/chips/via686a.c | 875 -------------------- drivers/i2c/chips/w83627ehf.c | 846 -------------------- drivers/i2c/chips/w83627hf.c | 1511 ----------------------------------- drivers/i2c/chips/w83781d.c | 1632 -------------------------------------- drivers/i2c/chips/w83l785ts.c | 328 -------- 68 files changed, 25444 insertions(+), 25444 deletions(-) create mode 100644 drivers/hwmon/adm1021.c create mode 100644 drivers/hwmon/adm1025.c create mode 100644 drivers/hwmon/adm1026.c create mode 100644 drivers/hwmon/adm1031.c create mode 100644 drivers/hwmon/adm9240.c create mode 100644 drivers/hwmon/asb100.c create mode 100644 drivers/hwmon/atxp1.c create mode 100644 drivers/hwmon/ds1621.c create mode 100644 drivers/hwmon/fscher.c create mode 100644 drivers/hwmon/fscpos.c create mode 100644 drivers/hwmon/gl518sm.c create mode 100644 drivers/hwmon/gl520sm.c create mode 100644 drivers/hwmon/it87.c create mode 100644 drivers/hwmon/lm63.c create mode 100644 drivers/hwmon/lm75.c create mode 100644 drivers/hwmon/lm75.h create mode 100644 drivers/hwmon/lm77.c create mode 100644 drivers/hwmon/lm78.c create mode 100644 drivers/hwmon/lm80.c create mode 100644 drivers/hwmon/lm83.c create mode 100644 drivers/hwmon/lm85.c create mode 100644 drivers/hwmon/lm87.c create mode 100644 drivers/hwmon/lm90.c create mode 100644 drivers/hwmon/lm92.c create mode 100644 drivers/hwmon/max1619.c create mode 100644 drivers/hwmon/pc87360.c create mode 100644 drivers/hwmon/sis5595.c create mode 100644 drivers/hwmon/smsc47b397.c create mode 100644 drivers/hwmon/smsc47m1.c create mode 100644 drivers/hwmon/via686a.c create mode 100644 drivers/hwmon/w83627ehf.c create mode 100644 drivers/hwmon/w83627hf.c create mode 100644 drivers/hwmon/w83781d.c create mode 100644 drivers/hwmon/w83l785ts.c delete mode 100644 drivers/i2c/chips/adm1021.c delete mode 100644 drivers/i2c/chips/adm1025.c delete mode 100644 drivers/i2c/chips/adm1026.c delete mode 100644 drivers/i2c/chips/adm1031.c delete mode 100644 drivers/i2c/chips/adm9240.c delete mode 100644 drivers/i2c/chips/asb100.c delete mode 100644 drivers/i2c/chips/atxp1.c delete mode 100644 drivers/i2c/chips/ds1621.c delete mode 100644 drivers/i2c/chips/fscher.c delete mode 100644 drivers/i2c/chips/fscpos.c delete mode 100644 drivers/i2c/chips/gl518sm.c delete mode 100644 drivers/i2c/chips/gl520sm.c delete mode 100644 drivers/i2c/chips/it87.c delete mode 100644 drivers/i2c/chips/lm63.c delete mode 100644 drivers/i2c/chips/lm75.c delete mode 100644 drivers/i2c/chips/lm75.h delete mode 100644 drivers/i2c/chips/lm77.c delete mode 100644 drivers/i2c/chips/lm78.c delete mode 100644 drivers/i2c/chips/lm80.c delete mode 100644 drivers/i2c/chips/lm83.c delete mode 100644 drivers/i2c/chips/lm85.c delete mode 100644 drivers/i2c/chips/lm87.c delete mode 100644 drivers/i2c/chips/lm90.c delete mode 100644 drivers/i2c/chips/lm92.c delete mode 100644 drivers/i2c/chips/max1619.c delete mode 100644 drivers/i2c/chips/pc87360.c delete mode 100644 drivers/i2c/chips/sis5595.c delete mode 100644 drivers/i2c/chips/smsc47b397.c delete mode 100644 drivers/i2c/chips/smsc47m1.c delete mode 100644 drivers/i2c/chips/via686a.c delete mode 100644 drivers/i2c/chips/w83627ehf.c delete mode 100644 drivers/i2c/chips/w83627hf.c delete mode 100644 drivers/i2c/chips/w83781d.c delete mode 100644 drivers/i2c/chips/w83l785ts.c (limited to 'drivers') diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c new file mode 100644 index 00000000000..d2c774c32f4 --- /dev/null +++ b/drivers/hwmon/adm1021.c @@ -0,0 +1,402 @@ +/* + adm1021.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); + +/* adm1021 constants specified below */ + +/* The adm1021 registers */ +/* Read-only */ +#define ADM1021_REG_TEMP 0x00 +#define ADM1021_REG_REMOTE_TEMP 0x01 +#define ADM1021_REG_STATUS 0x02 +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* These use different addresses for reading/writing */ +#define ADM1021_REG_CONFIG_R 0x03 +#define ADM1021_REG_CONFIG_W 0x09 +#define ADM1021_REG_CONV_RATE_R 0x04 +#define ADM1021_REG_CONV_RATE_W 0x0A +/* These are for the ADM1023's additional precision on the remote temp sensor */ +#define ADM1021_REG_REM_TEMP_PREC 0x010 +#define ADM1021_REG_REM_OFFSET 0x011 +#define ADM1021_REG_REM_OFFSET_PREC 0x012 +#define ADM1021_REG_REM_TOS_PREC 0x013 +#define ADM1021_REG_REM_THYST_PREC 0x014 +/* limits */ +#define ADM1021_REG_TOS_R 0x05 +#define ADM1021_REG_TOS_W 0x0B +#define ADM1021_REG_REMOTE_TOS_R 0x07 +#define ADM1021_REG_REMOTE_TOS_W 0x0D +#define ADM1021_REG_THYST_R 0x06 +#define ADM1021_REG_THYST_W 0x0C +#define ADM1021_REG_REMOTE_THYST_R 0x08 +#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* write-only */ +#define ADM1021_REG_ONESHOT 0x0F + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +/* Conversions note: 1021 uses normal integer signed-byte format*/ +#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) + +/* Initial values */ + +/* Note: Even though I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actually triggers an alarm instead of +clearing it. Weird, ey? --Phil */ + +/* Each client has this additional data */ +struct adm1021_data { + struct i2c_client client; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 temp_max; /* Register values */ + u8 temp_hyst; + u8 temp_input; + u8 remote_temp_max; + u8 remote_temp_hyst; + u8 remote_temp_input; + u8 alarms; + /* Special values for ADM1023 only */ + u8 remote_temp_prec; + u8 remote_temp_os_prec; + u8 remote_temp_hyst_prec; + u8 remote_temp_offset; + u8 remote_temp_offset_prec; +}; + +static int adm1021_attach_adapter(struct i2c_adapter *adapter); +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1021_init_client(struct i2c_client *client); +static int adm1021_detach_client(struct i2c_client *client); +static int adm1021_read_value(struct i2c_client *client, u8 reg); +static int adm1021_write_value(struct i2c_client *client, u8 reg, + u16 value); +static struct adm1021_data *adm1021_update_device(struct device *dev); + +/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ +static int read_only = 0; + + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1021_driver = { + .owner = THIS_MODULE, + .name = "adm1021", + .id = I2C_DRIVERID_ADM1021, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1021_attach_adapter, + .detach_client = adm1021_detach_client, +}; + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1021_data *data = adm1021_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); +show(remote_temp_max); +show(remote_temp_hyst); +show(remote_temp_input); + +#define show2(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1021_data *data = adm1021_update_device(dev); \ + return sprintf(buf, "%d\n", data->value); \ +} +show2(alarms); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm1021_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set(temp_max, ADM1021_REG_TOS_W); +set(temp_hyst, ADM1021_REG_THYST_W); +set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); +set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +static int adm1021_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1021_detect); +} + +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct adm1021_data *data; + int err = 0; + const char *type_name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1021_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + memset(data, 0, sizeof(struct adm1021_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1021_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { + err = -ENODEV; + goto error1; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + if (i == 0x41) + if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + kind = adm1023; + else + kind = adm1021; + else if (i == 0x49) + kind = thmc10; + else if (i == 0x23) + kind = gl523sm; + else if ((i == 0x4d) && + (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) + kind = max1617a; + else if (i == 0x54) + kind = mc1066; + /* LM84 Mfr ID in a different place, and it has more unused bits */ + else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 + && (kind == 0 /* skip extra detection */ + || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 + && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) + kind = lm84; + else + kind = max1617; + } + + if (kind == max1617) { + type_name = "max1617"; + } else if (kind == max1617a) { + type_name = "max1617a"; + } else if (kind == adm1021) { + type_name = "adm1021"; + } else if (kind == adm1023) { + type_name = "adm1023"; + } else if (kind == thmc10) { + type_name = "thmc10"; + } else if (kind == lm84) { + type_name = "lm84"; + } else if (kind == gl523sm) { + type_name = "gl523sm"; + } else if (kind == mc1066) { + type_name = "mc1066"; + } + + /* 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; + 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 error1; + + /* Initialize the ADM1021 chip */ + if (kind != lm84) + adm1021_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error1: + kfree(data); +error0: + return err; +} + +static void adm1021_init_client(struct i2c_client *client) +{ + /* Enable ADC and disable suspend mode */ + adm1021_write_value(client, ADM1021_REG_CONFIG_W, + adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); + /* Set Conversion rate to 1/sec (this can be tinkered with) */ + adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); +} + +static int adm1021_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; +} + +/* All registers are byte-sized */ +static int adm1021_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (!read_only) + return i2c_smbus_write_byte_data(client, reg, value); + return 0; +} + +static struct adm1021_data *adm1021_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting adm1021 update\n"); + + data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); + data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); + data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); + data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); + data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); + data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); + data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; + if (data->type == adm1023) { + data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); + data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); + data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1021_init(void) +{ + return i2c_add_driver(&adm1021_driver); +} + +static void __exit sensors_adm1021_exit(void) +{ + i2c_del_driver(&adm1021_driver); +} + +MODULE_AUTHOR ("Frodo Looijaard and " + "Philip Edelbrock "); +MODULE_DESCRIPTION("adm1021 driver"); +MODULE_LICENSE("GPL"); + +module_param(read_only, bool, 0); +MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); + +module_init(sensors_adm1021_init) +module_exit(sensors_adm1021_exit) diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c new file mode 100644 index 00000000000..e452d0daf90 --- /dev/null +++ b/drivers/hwmon/adm1025.c @@ -0,0 +1,577 @@ +/* + * adm1025.c + * + * Copyright (C) 2000 Chen-Yuan Wu + * Copyright (C) 2003-2004 Jean Delvare + * + * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6 + * voltages (including its own power source) and up to two temperatures + * (its own plus up to one external one). Voltages are scaled internally + * (which is not the common way) with ratios such that the nominal value + * of each voltage correspond to a register value of 192 (which means a + * resolution of about 0.5% of the nominal value). Temperature values are + * reported with a 1 deg resolution and a 3 deg accuracy. Complete + * datasheet can be obtained from Analog's website at: + * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html + * + * This driver also supports the ADM1025A, which differs from the ADM1025 + * only in that it has "open-drain VID inputs while the ADM1025 has + * on-chip 100k pull-ups on the VID inputs". It doesn't make any + * difference for us. + * + * This driver also supports the NE1619, a sensor chip made by Philips. + * That chip is similar to the ADM1025A, with a few differences. The only + * difference that matters to us is that the NE1619 has only two possible + * addresses while the ADM1025A has a third one. Complete datasheet can be + * obtained from Philips's website at: + * http://www.semiconductors.philips.com/pip/NE1619DS.html + * + * Since the ADM1025 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e. + * NE1619 has two possible addresses: 0x2c and 0x2d. + */ + +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_2(adm1025, ne1619); + +/* + * The ADM1025 registers + */ + +#define ADM1025_REG_MAN_ID 0x3E +#define ADM1025_REG_CHIP_ID 0x3F +#define ADM1025_REG_CONFIG 0x40 +#define ADM1025_REG_STATUS1 0x41 +#define ADM1025_REG_STATUS2 0x42 +#define ADM1025_REG_IN(nr) (0x20 + (nr)) +#define ADM1025_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define ADM1025_REG_IN_MIN(nr) (0x2C + (nr) * 2) +#define ADM1025_REG_TEMP(nr) (0x26 + (nr)) +#define ADM1025_REG_TEMP_HIGH(nr) (0x37 + (nr) * 2) +#define ADM1025_REG_TEMP_LOW(nr) (0x38 + (nr) * 2) +#define ADM1025_REG_VID 0x47 +#define ADM1025_REG_VID4 0x49 + +/* + * Conversions and various macros + * The ADM1025 uses signed 8-bit values for temperatures. + */ + +static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; + +#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ + (val) * 192 >= (scale) * 255 ? 255 : \ + ((val) * 192 + (scale)/2) / (scale)) + +#define TEMP_FROM_REG(reg) ((reg) * 1000) +#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ + (val) >= 126500 ? 127 : \ + (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + +/* + * Functions declaration + */ + +static int adm1025_attach_adapter(struct i2c_adapter *adapter); +static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1025_init_client(struct i2c_client *client); +static int adm1025_detach_client(struct i2c_client *client); +static struct adm1025_data *adm1025_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver adm1025_driver = { + .owner = THIS_MODULE, + .name = "adm1025", + .id = I2C_DRIVERID_ADM1025, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1025_attach_adapter, + .detach_client = adm1025_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct adm1025_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + u8 in[6]; /* register value */ + u8 in_max[6]; /* register value */ + u8 in_min[6]; /* register value */ + s8 temp[2]; /* register value */ + s8 temp_min[2]; /* register value */ + s8 temp_max[2]; /* register value */ + u16 alarms; /* register values, combined */ + u8 vid; /* register values, combined */ + u8 vrm; +}; + +/* + * Sysfs stuff + */ + +#define show_in(offset) \ +static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + in_scale[offset])); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); +show_in(0); +show_in(1); +show_in(2); +show_in(3); +show_in(4); +show_in(5); + +#define show_temp(offset) \ +static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ +}\ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); +show_temp(1); +show_temp(2); + +#define set_in(offset) \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ + data->in_min[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ + data->in_max[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in##offset##_max, set_in##offset##_max); +set_in(0); +set_in(1); +set_in(2); +set_in(3); +set_in(4); +set_in(5); + +#define set_temp(offset) \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_min[offset-1] = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ + data->temp_min[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_max[offset-1] = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ + data->temp_max[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); +set_temp(1); +set_temp(2); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ +static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +/* + * Real code + */ + +static int adm1025_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1025_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm1025_data *data; + int err = 0; + const char *name = ""; + u8 config; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm1025_data)); + + /* The common I2C client data is placed right before the + ADM1025-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1025_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); + if (kind < 0) { /* detection */ + if ((config & 0x80) != 0x00 + || (i2c_smbus_read_byte_data(new_client, + ADM1025_REG_STATUS1) & 0xC0) != 0x00 + || (i2c_smbus_read_byte_data(new_client, + ADM1025_REG_STATUS2) & 0xBC) != 0x00) { + dev_dbg(&adapter->dev, + "ADM1025 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u8 man_id, chip_id; + + man_id = i2c_smbus_read_byte_data(new_client, + ADM1025_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + ADM1025_REG_CHIP_ID); + + if (man_id == 0x41) { /* Analog Devices */ + if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ + kind = adm1025; + } + } else + if (man_id == 0xA1) { /* Philips */ + if (address != 0x2E + && (chip_id & 0xF0) == 0x20) { /* NE1619 */ + kind = ne1619; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == adm1025) { + name = "adm1025"; + } else if (kind == ne1619) { + name = "ne1619"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the ADM1025 chip */ + adm1025_init_client(new_client); + + /* Register sysfs hooks */ + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_alarms); + /* in1_ref is deprecated, remove after 2005-11-11 */ + device_create_file(&new_client->dev, &dev_attr_in1_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + + /* Pin 11 is either in4 (+12V) or VID4 */ + if (!(config & 0x20)) { + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + } + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void adm1025_init_client(struct i2c_client *client) +{ + u8 reg; + struct adm1025_data *data = i2c_get_clientdata(client); + int i; + + data->vrm = i2c_which_vrm(); + + /* + * Set high limits + * Usually we avoid setting limits on driver init, but it happens + * that the ADM1025 comes with stupid default limits (all registers + * set to 0). In case the chip has not gone through any limit + * setting yet, we better set the high limits to the max so that + * no alarm triggers. + */ + for (i=0; i<6; i++) { + reg = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MAX(i)); + if (reg == 0) + i2c_smbus_write_byte_data(client, + ADM1025_REG_IN_MAX(i), + 0xFF); + } + for (i=0; i<2; i++) { + reg = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_HIGH(i)); + if (reg == 0) + i2c_smbus_write_byte_data(client, + ADM1025_REG_TEMP_HIGH(i), + 0x7F); + } + + /* + * Start the conversions + */ + reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); + if (!(reg & 0x01)) + i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, + (reg&0x7E)|0x01); +} + +static int adm1025_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 struct adm1025_data *adm1025_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int i; + + dev_dbg(&client->dev, "Updating data.\n"); + for (i=0; i<6; i++) { + data->in[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN(i)); + data->in_min[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MIN(i)); + data->in_max[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MAX(i)); + } + for (i=0; i<2; i++) { + data->temp[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP(i)); + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_LOW(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_HIGH(i)); + } + data->alarms = i2c_smbus_read_byte_data(client, + ADM1025_REG_STATUS1) + | (i2c_smbus_read_byte_data(client, + ADM1025_REG_STATUS2) << 8); + data->vid = (i2c_smbus_read_byte_data(client, + ADM1025_REG_VID) & 0x0f) + | ((i2c_smbus_read_byte_data(client, + ADM1025_REG_VID4) & 0x01) << 4); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1025_init(void) +{ + return i2c_add_driver(&adm1025_driver); +} + +static void __exit sensors_adm1025_exit(void) +{ + i2c_del_driver(&adm1025_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("ADM1025 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm1025_init); +module_exit(sensors_adm1025_exit); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c new file mode 100644 index 00000000000..3c85fe150cd --- /dev/null +++ b/drivers/hwmon/adm1026.c @@ -0,0 +1,1714 @@ +/* + adm1026.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (C) 2002, 2003 Philip Pokorny + Copyright (C) 2004 Justin Thiessen + + Chip details at: + + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(adm1026); + +static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +module_param_array(gpio_input,int,NULL,0); +MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); +module_param_array(gpio_output,int,NULL,0); +MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " + "outputs"); +module_param_array(gpio_inverted,int,NULL,0); +MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " + "inverted"); +module_param_array(gpio_normal,int,NULL,0); +MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " + "normal/non-inverted"); +module_param_array(gpio_fan,int,NULL,0); +MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); + +/* Many ADM1026 constants specified below */ + +/* The ADM1026 registers */ +#define ADM1026_REG_CONFIG1 0x00 +#define CFG1_MONITOR 0x01 +#define CFG1_INT_ENABLE 0x02 +#define CFG1_INT_CLEAR 0x04 +#define CFG1_AIN8_9 0x08 +#define CFG1_THERM_HOT 0x10 +#define CFG1_DAC_AFC 0x20 +#define CFG1_PWM_AFC 0x40 +#define CFG1_RESET 0x80 +#define ADM1026_REG_CONFIG2 0x01 +/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ +#define ADM1026_REG_CONFIG3 0x07 +#define CFG3_GPIO16_ENABLE 0x01 +#define CFG3_CI_CLEAR 0x02 +#define CFG3_VREF_250 0x04 +#define CFG3_GPIO16_DIR 0x40 +#define CFG3_GPIO16_POL 0x80 +#define ADM1026_REG_E2CONFIG 0x13 +#define E2CFG_READ 0x01 +#define E2CFG_WRITE 0x02 +#define E2CFG_ERASE 0x04 +#define E2CFG_ROM 0x08 +#define E2CFG_CLK_EXT 0x80 + +/* There are 10 general analog inputs and 7 dedicated inputs + * They are: + * 0 - 9 = AIN0 - AIN9 + * 10 = Vbat + * 11 = 3.3V Standby + * 12 = 3.3V Main + * 13 = +5V + * 14 = Vccp (CPU core voltage) + * 15 = +12V + * 16 = -12V + */ +static u16 ADM1026_REG_IN[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f + }; +static u16 ADM1026_REG_IN_MIN[] = { + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, + 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; +static u16 ADM1026_REG_IN_MAX[] = { + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x47 + }; + +/* Temperatures are: + * 0 - Internal + * 1 - External 1 + * 2 - External 2 + */ +static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 }; +static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; +static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; +static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; +static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; +static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; + +#define ADM1026_REG_FAN(nr) (0x38 + (nr)) +#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) +#define ADM1026_REG_FAN_DIV_0_3 0x02 +#define ADM1026_REG_FAN_DIV_4_7 0x03 + +#define ADM1026_REG_DAC 0x04 +#define ADM1026_REG_PWM 0x05 + +#define ADM1026_REG_GPIO_CFG_0_3 0x08 +#define ADM1026_REG_GPIO_CFG_4_7 0x09 +#define ADM1026_REG_GPIO_CFG_8_11 0x0a +#define ADM1026_REG_GPIO_CFG_12_15 0x0b +/* CFG_16 in REG_CFG3 */ +#define ADM1026_REG_GPIO_STATUS_0_7 0x24 +#define ADM1026_REG_GPIO_STATUS_8_15 0x25 +/* STATUS_16 in REG_STATUS4 */ +#define ADM1026_REG_GPIO_MASK_0_7 0x1c +#define ADM1026_REG_GPIO_MASK_8_15 0x1d +/* MASK_16 in REG_MASK4 */ + +#define ADM1026_REG_COMPANY 0x16 +#define ADM1026_REG_VERSTEP 0x17 +/* These are the recognized values for the above regs */ +#define ADM1026_COMPANY_ANALOG_DEV 0x41 +#define ADM1026_VERSTEP_GENERIC 0x40 +#define ADM1026_VERSTEP_ADM1026 0x44 + +#define ADM1026_REG_MASK1 0x18 +#define ADM1026_REG_MASK2 0x19 +#define ADM1026_REG_MASK3 0x1a +#define ADM1026_REG_MASK4 0x1b + +#define ADM1026_REG_STATUS1 0x20 +#define ADM1026_REG_STATUS2 0x21 +#define ADM1026_REG_STATUS3 0x22 +#define ADM1026_REG_STATUS4 0x23 + +#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6 +#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 +#define ADM1026_PWM_MAX 255 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled acording to built-in resistors. These are the + * voltages corresponding to 3/4 of full scale (192 or 0xc0) + * NOTE: The -12V input needs an additional factor to account + * for the Vref pullup resistor. + * NEG12_OFFSET = SCALE * Vref / V-192 - Vref + * = 13875 * 2.50 / 1.875 - 2500 + * = 16000 + * + * The values in this table are based on Table II, page 15 of the + * datasheet. + */ +static int adm1026_scaling[] = { /* .001 Volts */ + 2250, 2250, 2250, 2250, 2250, 2250, + 1875, 1875, 1875, 1875, 3000, 3330, + 3330, 4995, 2250, 12000, 13875 + }; +#define NEG12_OFFSET 16000 +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) +#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ + 0,255)) +#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) + +/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses + * and we assume a 2 pulse-per-rev fan tach signal + * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 + */ +#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ + (div)),1,254)) +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ + (div))) +#define DIV_FROM_REG(val) (1<<(val)) +#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) + +/* Temperature is reported in 1 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ + -127,127)) +#define TEMP_FROM_REG(val) ((val) * 1000) +#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ + -127,127)) +#define OFFSET_FROM_REG(val) ((val) * 1000) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + +#define PWM_MIN_TO_REG(val) ((val) & 0xf0) +#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) + +/* Analog output is a voltage, and scaled to millivolts. The datasheet + * indicates that the DAC could be used to drive the fans, but in our + * example board (Arima HDAMA) it isn't connected to the fans at all. + */ +#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) +#define DAC_FROM_REG(val) (((val)*2500)/255) + +/* Typically used with systems using a v9.1 VRM spec ? */ +#define ADM1026_INIT_VRM 91 + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * So, we keep the config data up to date in the cache + * when it is written and only sample it once every 5 *minutes* + */ +#define ADM1026_DATA_INTERVAL (1 * HZ) +#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) + +/* We allow for multiple chips in a single system. + * + * For each registered ADM1026, we need to keep state information + * at client->data. The adm1026_data structure is dynamically + * allocated, when a new client structure is allocated. */ + +struct pwm_data { + u8 pwm; + u8 enable; + u8 auto_pwm_min; +}; + +struct adm1026_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[17]; /* Register value */ + u8 in_max[17]; /* Register value */ + u8 in_min[17]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_tmin[3]; /* Register value */ + s8 temp_crit[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u8 fan[8]; /* Register value */ + u8 fan_min[8]; /* Register value */ + u8 fan_div[8]; /* Decoded value */ + struct pwm_data pwm1; /* Pwm control values */ + int vid; /* Decoded value */ + u8 vrm; /* VRM version */ + u8 analog_out; /* Register value (DAC) */ + long alarms; /* Register encoding, combined */ + long alarm_mask; /* Register encoding, combined */ + long gpio; /* Register encoding, combined */ + long gpio_mask; /* Register encoding, combined */ + u8 gpio_config[17]; /* Decoded value */ + u8 config1; /* Register value */ + u8 config2; /* Register value */ + u8 config3; /* Register value */ +}; + +static int adm1026_attach_adapter(struct i2c_adapter *adapter); +static int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind); +static int adm1026_detach_client(struct i2c_client *client); +static int adm1026_read_value(struct i2c_client *client, u8 register); +static int adm1026_write_value(struct i2c_client *client, u8 register, + int value); +static void adm1026_print_gpio(struct i2c_client *client); +static void adm1026_fixup_gpio(struct i2c_client *client); +static struct adm1026_data *adm1026_update_device(struct device *dev); +static void adm1026_init_client(struct i2c_client *client); + + +static struct i2c_driver adm1026_driver = { + .owner = THIS_MODULE, + .name = "adm1026", + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1026_attach_adapter, + .detach_client = adm1026_detach_client, +}; + +int adm1026_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) { + return 0; + } + return i2c_detect(adapter, &addr_data, adm1026_detect); +} + +int adm1026_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(client); + return 0; +} + +int adm1026_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + if (reg < 0x80) { + /* "RAM" locations */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff; + } else { + /* EEPROM, do nothing */ + res = 0; + } + return res; +} + +int adm1026_write_value(struct i2c_client *client, u8 reg, int value) +{ + int res; + + if (reg < 0x80) { + /* "RAM" locations */ + res = i2c_smbus_write_byte_data(client, reg, value); + } else { + /* EEPROM, do nothing */ + res = 0; + } + return res; +} + +void adm1026_init_client(struct i2c_client *client) +{ + int value, i; + struct adm1026_data *data = i2c_get_clientdata(client); + + 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, "ADM1026_REG_CONFIG1 is: 0x%02x\n", + data->config1); + if ((data->config1 & CFG1_MONITOR) == 0) { + dev_dbg(&client->dev, "Monitoring not currently " + "enabled.\n"); + } + if (data->config1 & CFG1_INT_ENABLE) { + dev_dbg(&client->dev, "SMBALERT interrupts are " + "enabled.\n"); + } + if (data->config1 & CFG1_AIN8_9) { + dev_dbg(&client->dev, "in8 and in9 enabled. " + "temp3 disabled.\n"); + } else { + dev_dbg(&client->dev, "temp3 enabled. in8 and " + "in9 disabled.\n"); + } + if (data->config1 & CFG1_THERM_HOT) { + 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, "GPIO16 enabled. THERM" + "pin disabled.\n"); + } else { + dev_dbg(&client->dev, "THERM pin enabled. " + "GPIO16 disabled.\n"); + } + if (data->config3 & CFG3_VREF_250) { + dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); + } else { + dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); + } + /* Read and pick apart the existing GPIO configuration */ + value = 0; + for (i = 0;i <= 15;++i) { + if ((i & 0x03) == 0) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4); + } + data->gpio_config[i] = value & 0x03; + value >>= 2; + } + data->gpio_config[16] = (data->config3 >> 6) & 0x03; + + /* ... and then print it */ + adm1026_print_gpio(client); + + /* If the user asks us to reprogram the GPIO config, then + * do it now. + */ + if (gpio_input[0] != -1 || gpio_output[0] != -1 + || gpio_inverted[0] != -1 || gpio_normal[0] != -1 + || gpio_fan[0] != -1) { + adm1026_fixup_gpio(client); + } + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms, fans and zones. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is 100% PWM, no + * control and will suffice until 'sensors -s' + * can be run by the user. We DO set the default + * value for pwm1.auto_pwm_min to its maximum + * so that enabling automatic pwm fan control + * without first setting a value for pwm1.auto_pwm_min + * will not result in potentially dangerous fan speed decrease. + */ + data->pwm1.auto_pwm_min=255; + /* Start monitoring */ + 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, "Setting CONFIG to: 0x%02x\n", value); + data->config1 = value; + adm1026_write_value(client, ADM1026_REG_CONFIG1, value); + + /* initialize fan_div[] to hardware defaults */ + value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | + (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); + for (i = 0;i <= 7;++i) { + data->fan_div[i] = DIV_FROM_REG(value & 0x03); + value >>= 2; + } +} + +void adm1026_print_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + + dev_dbg(&client->dev, "GPIO config is:"); + for (i = 0;i <= 7;++i) { + if (data->config2 & (1 << i)) { + 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, "\tFAN%d\n", i); + } + } + for (i = 8;i <= 15;++i) { + 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%sGP%s16\n", + data->gpio_config[16] & 0x02 ? "" : "!", + data->gpio_config[16] & 0x01 ? "OUT" : "IN"); + } else { + /* GPIO16 is THERM */ + dev_dbg(&client->dev, "\tTHERM\n"); + } +} + +void adm1026_fixup_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + int value; + + /* Make the changes requested. */ + /* We may need to unlock/stop monitoring or soft-reset the + * chip before we can make changes. This hasn't been + * tested much. FIXME + */ + + /* Make outputs */ + for (i = 0;i <= 16;++i) { + if (gpio_output[i] >= 0 && gpio_output[i] <= 16) { + data->gpio_config[gpio_output[i]] |= 0x01; + } + /* if GPIO0-7 is output, it isn't a FAN tach */ + if (gpio_output[i] >= 0 && gpio_output[i] <= 7) { + data->config2 |= 1 << gpio_output[i]; + } + } + + /* Input overrides output */ + for (i = 0;i <= 16;++i) { + if (gpio_input[i] >= 0 && gpio_input[i] <= 16) { + data->gpio_config[gpio_input[i]] &= ~ 0x01; + } + /* if GPIO0-7 is input, it isn't a FAN tach */ + if (gpio_input[i] >= 0 && gpio_input[i] <= 7) { + data->config2 |= 1 << gpio_input[i]; + } + } + + /* Inverted */ + for (i = 0;i <= 16;++i) { + if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { + data->gpio_config[gpio_inverted[i]] &= ~ 0x02; + } + } + + /* Normal overrides inverted */ + for (i = 0;i <= 16;++i) { + if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { + data->gpio_config[gpio_normal[i]] |= 0x02; + } + } + + /* Fan overrides input and output */ + for (i = 0;i <= 7;++i) { + if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) { + data->config2 &= ~(1 << gpio_fan[i]); + } + } + + /* Write new configs to registers */ + adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); + data->config3 = (data->config3 & 0x3f) + | ((data->gpio_config[16] & 0x03) << 6); + adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); + for (i = 15, value = 0;i >= 0;--i) { + value <<= 2; + value |= data->gpio_config[i] & 0x03; + if ((i & 0x03) == 0) { + adm1026_write_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4, + value); + value = 0; + } + } + + /* Print the new config */ + adm1026_print_gpio(client); +} + + +static struct adm1026_data *adm1026_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + long value, alarms, gpio; + + down(&data->update_lock); + if (!data->valid + || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { + /* Things that change quickly */ + 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]); + } + + for (i = 0;i <= 7;++i) { + data->fan[i] = + adm1026_read_value(client, ADM1026_REG_FAN(i)); + } + + for (i = 0;i <= 2;++i) { + /* NOTE: temp[] is s8 and we assume 2's complement + * "conversion" in the assignment */ + data->temp[i] = + adm1026_read_value(client, ADM1026_REG_TEMP[i]); + } + + data->pwm1.pwm = adm1026_read_value(client, + ADM1026_REG_PWM); + data->analog_out = adm1026_read_value(client, + ADM1026_REG_DAC); + /* GPIO16 is MSbit of alarms, move it to gpio */ + alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + alarms &= 0x7f; + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); + data->alarms = alarms; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_STATUS_8_15); + gpio <<= 8; + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_STATUS_0_7); + data->gpio = gpio; + + data->last_reading = jiffies; + }; /* last_reading */ + + if (!data->valid || + time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { + /* Things that don't change often */ + 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]); + data->in_max[i] = adm1026_read_value(client, + ADM1026_REG_IN_MAX[i]); + } + + value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) + | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) + << 8); + for (i = 0;i <= 7;++i) { + data->fan_min[i] = adm1026_read_value(client, + ADM1026_REG_FAN_MIN(i)); + data->fan_div[i] = DIV_FROM_REG(value & 0x03); + value >>= 2; + } + + for (i = 0; i <= 2; ++i) { + /* NOTE: temp_xxx[] are s8 and we assume 2's + * complement "conversion" in the assignment + */ + data->temp_min[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_MIN[i]); + data->temp_max[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_MAX[i]); + data->temp_tmin[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_TMIN[i]); + data->temp_crit[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_THERM[i]); + data->temp_offset[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_OFFSET[i]); + } + + /* Read the STATUS/alarm masks */ + alarms = adm1026_read_value(client, ADM1026_REG_MASK4); + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + alarms = (alarms & 0x7f) << 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); + data->alarm_mask = alarms; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_MASK_8_15); + gpio <<= 8; + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); + data->gpio_mask = gpio; + + /* Read various values from CONFIG1 */ + data->config1 = adm1026_read_value(client, + ADM1026_REG_CONFIG1); + if (data->config1 & CFG1_PWM_AFC) { + data->pwm1.enable = 2; + data->pwm1.auto_pwm_min = + PWM_MIN_FROM_REG(data->pwm1.pwm); + } + /* Read the GPIO config */ + data->config2 = adm1026_read_value(client, + ADM1026_REG_CONFIG2); + data->config3 = adm1026_read_value(client, + ADM1026_REG_CONFIG3); + data->gpio_config[16] = (data->config3 >> 6) & 0x03; + + value = 0; + for (i = 0;i <= 15;++i) { + if ((i & 0x03) == 0) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4); + } + data->gpio_config[i] = value & 0x03; + value >>= 2; + } + + data->last_config = jiffies; + }; /* last_config */ + + dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); + data->vid = (data->gpio >> 11) & 0x1f; + data->valid = 1; + up(&data->update_lock); + return data; +} + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); +} +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); +} +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = INS_TO_REG(nr, val); + adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); +} +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = INS_TO_REG(nr, val); + adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define in_reg(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \ + NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); + + +in_reg(0); +in_reg(1); +in_reg(2); +in_reg(3); +in_reg(4); +in_reg(5); +in_reg(6); +in_reg(7); +in_reg(8); +in_reg(9); +in_reg(10); +in_reg(11); +in_reg(12); +in_reg(13); +in_reg(14); +in_reg(15); + +static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - + NEG12_OFFSET); +} +static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) + - NEG12_OFFSET); +} +static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); + up(&data->update_lock); + return count; +} +static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) + - NEG12_OFFSET); +} +static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); + up(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); +static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); +static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); + + + + +/* Now add fan read/write functions */ + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + data->fan_div[nr])); +} +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + data->fan_div[nr])); +} +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]); + adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); + +fan_offset(1); +fan_offset(2); +fan_offset(3); +fan_offset(4); +fan_offset(5); +fan_offset(6); +fan_offset(7); +fan_offset(8); + +/* Adjust fan_min to account for new fan divisor */ +static void fixup_fan_min(struct device *dev, int fan, int old_div) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int new_min; + int new_div = data->fan_div[fan]; + + /* 0 and 0xff are special. Don't adjust them */ + if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { + return; + } + + new_min = data->fan_min[fan] * old_div / new_div; + new_min = SENSORS_LIMIT(new_min, 1, 254); + data->fan_min[fan] = new_min; + adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); +} + +/* Now add fan_div read/write functions */ +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->fan_div[nr]); +} +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val,orig_div,new_div,shift; + + val = simple_strtol(buf, NULL, 10); + new_div = DIV_TO_REG(val); + if (new_div == 0) { + return -EINVAL; + } + down(&data->update_lock); + orig_div = data->fan_div[nr]; + data->fan_div[nr] = DIV_FROM_REG(new_div); + + if (nr < 4) { /* 0 <= nr < 4 */ + shift = 2 * nr; + adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, + ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) | + (new_div << shift))); + } else { /* 3 < nr < 8 */ + shift = 2 * (nr - 4); + adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, + ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) | + (new_div << shift))); + } + + if (data->fan_div[nr] != orig_div) { + fixup_fan_min(dev,nr,orig_div); + } + up(&data->update_lock); + return count; +} + +#define fan_offset_div(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); + +fan_offset_div(1); +fan_offset_div(2); +fan_offset_div(3); +fan_offset_div(4); +fan_offset_div(5); +fan_offset_div(6); +fan_offset_div(7); +fan_offset_div(8); + +/* Temps */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); +} +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); +} +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr], + data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); +} +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr], + data->temp_max[nr]); + up(&data->update_lock); + return count; +} + +#define temp_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ + NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); + + +temp_reg(1); +temp_reg(2); +temp_reg(3); + +static ssize_t show_temp_offset(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); +} +static ssize_t set_temp_offset(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_offset[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr], + data->temp_offset[nr]); + up(&data->update_lock); + return count; +} + +#define temp_offset_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ + show_temp_offset, set_temp_offset, offset - 1); + +temp_offset_reg(1); +temp_offset_reg(2); +temp_offset_reg(3); + +static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG( + ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); +} +static ssize_t show_temp_auto_point2_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + + ADM1026_FAN_CONTROL_TEMP_RANGE)); +} +static ssize_t show_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); +} +static ssize_t set_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_tmin[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr], + data->temp_tmin[nr]); + up(&data->update_lock); + return count; +} + +#define temp_auto_point(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ + show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ + show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ + show_temp_auto_point2_temp, NULL, offset - 1); + +temp_auto_point(1); +temp_auto_point(2); +temp_auto_point(3); + +static ssize_t show_temp_crit_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); +} +static ssize_t set_temp_crit_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + if ((val == 1) || (val==0)) { + down(&data->update_lock); + data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); + adm1026_write_value(client, ADM1026_REG_CONFIG1, + data->config1); + up(&data->update_lock); + } + return count; +} + +#define temp_crit_enable(offset) \ +static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \ + show_temp_crit_enable, set_temp_crit_enable); + +temp_crit_enable(1); +temp_crit_enable(2); +temp_crit_enable(3); + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); +} +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_crit[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr], + data->temp_crit[nr]); + up(&data->update_lock); + return count; +} + +#define temp_crit_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_crit, set_temp_crit, offset - 1); + +temp_crit_reg(1); +temp_crit_reg(2); +temp_crit_reg(3); + +static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); +} +static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->analog_out = DAC_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, + set_analog_out_reg); + +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); +} +/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ +static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); + +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->vrm); +} +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + + data->vrm = simple_strtol(buf, NULL, 10); + return count; +} + +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); + +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf, "%ld\n", (long) (data->alarms)); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + +static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->alarm_mask); +} +static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + unsigned long mask; + + down(&data->update_lock); + data->alarm_mask = val & 0x7fffffff; + mask = data->alarm_mask + | (data->gpio_mask & 0x10000 ? 0x80000000 : 0); + adm1026_write_value(client, ADM1026_REG_MASK1, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK2, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK3, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK4, + mask & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, + set_alarm_mask); + + +static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->gpio); +} +static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + long gpio; + + down(&data->update_lock); + data->gpio = val & 0x1ffff; + gpio = data->gpio; + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); + gpio >>= 8; + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff); + gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f); + adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); + + +static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->gpio_mask); +} +static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + long mask; + + down(&data->update_lock); + data->gpio_mask = val & 0x1ffff; + mask = data->gpio_mask; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff); + mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f); + adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); + +static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); +} +static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + + if (data->pwm1.enable == 1) { + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm1.pwm = PWM_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); + up(&data->update_lock); + } + return count; +} +static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); +} +static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255); + if (data->pwm1.enable == 2) { /* apply immediately */ + data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); + } + up(&data->update_lock); + return count; +} +static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%d\n", ADM1026_PWM_MAX); +} +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->pwm1.enable); +} +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int old_enable; + + if ((val >= 0) && (val < 3)) { + down(&data->update_lock); + old_enable = data->pwm1.enable; + data->pwm1.enable = val; + data->config1 = (data->config1 & ~CFG1_PWM_AFC) + | ((val == 2) ? CFG1_PWM_AFC : 0); + adm1026_write_value(client, ADM1026_REG_CONFIG1, + data->config1); + if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ + data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm1.pwm); + } else if (!((old_enable == 1) && (val == 1))) { + /* set pwm to safe value */ + data->pwm1.pwm = 255; + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm1.pwm); + } + up(&data->update_lock); + } + return count; +} + +/* enable PWM fan control */ +static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); +static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); +static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); + +static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); + +int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int company, verstep; + struct i2c_client *new_client; + struct adm1026_data *data; + int err = 0; + const char *type_name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto exit; + }; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1026_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct adm1026_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1026_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); + verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); + + dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep); + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { + dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x " + "...\n", i2c_adapter_id(adapter), address); + if (company == ADM1026_COMPANY_ANALOG_DEV + && verstep == ADM1026_VERSTEP_ADM1026) { + kind = adm1026; + } else if (company == ADM1026_COMPANY_ANALOG_DEV + && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { + dev_err(&adapter->dev, ": Unrecognized stepping " + "0x%02x. Defaulting to ADM1026.\n", verstep); + kind = adm1026; + } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { + dev_err(&adapter->dev, ": Found version/stepping " + "0x%02x. Assuming generic ADM1026.\n", + verstep); + kind = any_chip; + } else { + dev_dbg(&new_client->dev, ": Autodetection " + "failed\n"); + /* Not an ADM1026 ... */ + if (kind == 0) { /* User used force=x,y */ + dev_err(&adapter->dev, "Generic ADM1026 not " + "found at %d,0x%02x. Try " + "force_adm1026.\n", + i2c_adapter_id(adapter), address); + } + err = 0; + goto exitfree; + } + } + + /* Fill in the chip specific driver values */ + switch (kind) { + case any_chip : + type_name = "adm1026"; + break; + case adm1026 : + type_name = "adm1026"; + break; + default : + dev_err(&adapter->dev, ": Internal error, invalid " + "kind (%d)!", kind); + err = -EFAULT; + goto exitfree; + } + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + + /* Fill in the remaining client fields */ + data->type = kind; + 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 exitfree; + + /* Set the VRM version */ + data->vrm = i2c_which_vrm(); + + /* Initialize the ADM1026 chip */ + adm1026_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); + device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); + /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ + device_create_file(&new_client->dev, &dev_attr_vid); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_alarm_mask); + device_create_file(&new_client->dev, &dev_attr_gpio); + device_create_file(&new_client->dev, &dev_attr_gpio_mask); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + device_create_file(&new_client->dev, &dev_attr_pwm3_enable); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_analog_out); + return 0; + + /* Error out and cleanup code */ +exitfree: + kfree(new_client); +exit: + return err; +} +static int __init sm_adm1026_init(void) +{ + return i2c_add_driver(&adm1026_driver); +} + +static void __exit sm_adm1026_exit(void) +{ + i2c_del_driver(&adm1026_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny , " + "Justin Thiessen "); +MODULE_DESCRIPTION("ADM1026 driver"); + +module_init(sm_adm1026_init); +module_exit(sm_adm1026_exit); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c new file mode 100644 index 00000000000..9168e983ca1 --- /dev/null +++ b/drivers/hwmon/adm1031.c @@ -0,0 +1,977 @@ +/* + adm1031.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Based on lm75.c and lm85.c + Supports adm1030 / adm1031 + Copyright (C) 2004 Alexandre d'Alton + Reworked by Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +/* Following macros takes channel parameter starting from 0 to 2 */ +#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) +#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) +#define ADM1031_REG_PWM (0x22) +#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) + +#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) +#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) +#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) + +#define ADM1031_REG_TEMP(nr) (0xa + (nr)) +#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) + +#define ADM1031_REG_STATUS(nr) (0x2 + (nr)) + +#define ADM1031_REG_CONF1 0x0 +#define ADM1031_REG_CONF2 0x1 +#define ADM1031_REG_EXT_TEMP 0x6 + +#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ +#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ +#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ + +#define ADM1031_CONF2_PWM1_ENABLE 0x01 +#define ADM1031_CONF2_PWM2_ENABLE 0x02 +#define ADM1031_CONF2_TACH1_ENABLE 0x04 +#define ADM1031_CONF2_TACH2_ENABLE 0x08 +#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(adm1030, adm1031); + +typedef u8 auto_chan_table_t[8][2]; + +/* Each client has this additional data */ +struct adm1031_data { + struct i2c_client client; + struct semaphore update_lock; + int chip_type; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + /* The chan_select_table contains the possible configurations for + * auto fan control. + */ + auto_chan_table_t *chan_select_table; + u16 alarm; + u8 conf1; + u8 conf2; + u8 fan[2]; + u8 fan_div[2]; + u8 fan_min[2]; + u8 pwm[2]; + u8 old_pwm[2]; + s8 temp[3]; + u8 ext_temp[3]; + u8 auto_temp[3]; + u8 auto_temp_min[3]; + u8 auto_temp_off[3]; + u8 auto_temp_max[3]; + s8 temp_min[3]; + s8 temp_max[3]; + s8 temp_crit[3]; +}; + +static int adm1031_attach_adapter(struct i2c_adapter *adapter); +static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1031_init_client(struct i2c_client *client); +static int adm1031_detach_client(struct i2c_client *client); +static struct adm1031_data *adm1031_update_device(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1031_driver = { + .owner = THIS_MODULE, + .name = "adm1031", + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1031_attach_adapter, + .detach_client = adm1031_detach_client, +}; + +static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static inline int +adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + + +#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ + ((val + 500) / 1000))) + +#define TEMP_FROM_REG(val) ((val) * 1000) + +#define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) + +#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) + +static int FAN_TO_REG(int reg, int div) +{ + int tmp; + tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); + return tmp > 255 ? 255 : tmp; +} + +#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) + +#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) +#define PWM_FROM_REG(val) ((val) << 4) + +#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) +#define FAN_CHAN_TO_REG(val, reg) \ + (((reg) & 0x1F) | (((val) << 5) & 0xe0)) + +#define AUTO_TEMP_MIN_TO_REG(val, reg) \ + ((((val)/500) & 0xf8)|((reg) & 0x7)) +#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) +#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) + +#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) + +#define AUTO_TEMP_OFF_FROM_REG(reg) \ + (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) + +#define AUTO_TEMP_MAX_FROM_REG(reg) \ + (AUTO_TEMP_RANGE_FROM_REG(reg) + \ + AUTO_TEMP_MIN_FROM_REG(reg)) + +static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) +{ + int ret; + int range = val - AUTO_TEMP_MIN_FROM_REG(reg); + + range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm); + ret = ((reg & 0xf8) | + (range < 10000 ? 0 : + range < 20000 ? 1 : + range < 40000 ? 2 : range < 80000 ? 3 : 4)); + return ret; +} + +/* FAN auto control */ +#define GET_FAN_AUTO_BITFIELD(data, idx) \ + (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] + +/* The tables below contains the possible values for the auto fan + * control bitfields. the index in the table is the register value. + * MSb is the auto fan control enable bit, so the four first entries + * in the table disables auto fan control when both bitfields are zero. + */ +static auto_chan_table_t auto_channel_select_table_adm1031 = { + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2 /*0b010 */ , 4 /*0b100 */ }, + {2 /*0b010 */ , 2 /*0b010 */ }, + {4 /*0b100 */ , 4 /*0b100 */ }, + {7 /*0b111 */ , 7 /*0b111 */ }, +}; + +static auto_chan_table_t auto_channel_select_table_adm1030 = { + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2 /*0b10 */ , 0}, + {0xff /*invalid */ , 0}, + {0xff /*invalid */ , 0}, + {3 /*0b11 */ , 0}, +}; + +/* That function checks if a bitfield is valid and returns the other bitfield + * nearest match if no exact match where found. + */ +static int +get_fan_auto_nearest(struct adm1031_data *data, + int chan, u8 val, u8 reg, u8 * new_reg) +{ + int i; + int first_match = -1, exact_match = -1; + u8 other_reg_val = + (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; + + if (val == 0) { + *new_reg = 0; + return 0; + } + + for (i = 0; i < 8; i++) { + if ((val == (*data->chan_select_table)[i][chan]) && + ((*data->chan_select_table)[i][chan ? 0 : 1] == + other_reg_val)) { + /* We found an exact match */ + exact_match = i; + break; + } else if (val == (*data->chan_select_table)[i][chan] && + first_match == -1) { + /* Save the first match in case of an exact match has not been + * found + */ + first_match = i; + } + } + + if (exact_match >= 0) { + *new_reg = exact_match; + } else if (first_match >= 0) { + *new_reg = first_match; + } else { + return -EINVAL; + } + return 0; +} + +static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); +} + +static ssize_t +set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + u8 reg; + int ret; + u8 old_fan_mode; + + old_fan_mode = data->conf1; + + down(&data->update_lock); + + if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { + up(&data->update_lock); + return ret; + } + if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ + (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { + if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ + /* Switch to Auto Fan Mode + * Save PWM registers + * Set PWM registers to 33% Both */ + data->old_pwm[0] = data->pwm[0]; + data->old_pwm[1] = data->pwm[1]; + adm1031_write_value(client, ADM1031_REG_PWM, 0x55); + } else { + /* Switch to Manual Mode */ + data->pwm[0] = data->old_pwm[0]; + data->pwm[1] = data->old_pwm[1]; + /* Restore PWM registers */ + adm1031_write_value(client, ADM1031_REG_PWM, + data->pwm[0] | (data->pwm[1] << 4)); + } + } + data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); + adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); + up(&data->update_lock); + return count; +} + +#define fan_auto_channel_offset(offset) \ +static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_auto_channel(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_auto_channel(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ + show_fan_auto_channel_##offset, \ + set_fan_auto_channel_##offset) + +fan_auto_channel_offset(1); +fan_auto_channel_offset(2); + +/* Auto Temps */ +static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); +} +static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); +} +static ssize_t +set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); + adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), + data->auto_temp[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); +} +static ssize_t +set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); + adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), + data->temp_max[nr]); + up(&data->update_lock); + return count; +} + +#define auto_temp_reg(offset) \ +static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_off(dev, buf, offset - 1); \ +} \ +static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_auto_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_auto_temp_max(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ + show_auto_temp_##offset##_off, NULL); \ +static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ +static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) + +auto_temp_reg(1); +auto_temp_reg(2); +auto_temp_reg(3); + +/* pwm */ +static ssize_t show_pwm(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} +static ssize_t +set_pwm(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int reg; + + down(&data->update_lock); + if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && + (((val>>4) & 0xf) != 5)) { + /* In automatic mode, the only PWM accepted is 33% */ + up(&data->update_lock); + return -EINVAL; + } + data->pwm[nr] = PWM_TO_REG(val); + reg = adm1031_read_value(client, ADM1031_REG_PWM); + adm1031_write_value(client, ADM1031_REG_PWM, + nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) + : (data->pwm[nr] & 0xf) | (reg & 0xf0)); + up(&data->update_lock); + return count; +} + +#define pwm_reg(offset) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset) + +pwm_reg(1); +pwm_reg(2); + +/* Fans */ + +/* + * That function checks the cases where the fan reading is not + * relevant. It is used to provide 0 as fan reading when the fan is + * not supposed to run + */ +static int trust_fan_readings(struct adm1031_data *data, int chan) +{ + int res = 0; + + if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { + switch (data->conf1 & 0x60) { + case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ + res = data->temp[chan+1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); + break; + case 0x20: /* remote temp1 controls both fans */ + res = + data->temp[1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); + break; + case 0x40: /* remote temp2 controls both fans */ + res = + data->temp[2] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); + break; + case 0x60: /* max controls both fans */ + res = + data->temp[0] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) + || data->temp[1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) + || (data->chip_type == adm1031 + && data->temp[2] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); + break; + } + } else { + res = data->pwm[chan] > 0; + } + return res; +} + + +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + int value; + + value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], + FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; + return sprintf(buf, "%d\n", value); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t +set_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + if (val) { + data->fan_min[nr] = + FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); + } else { + data->fan_min[nr] = 0xff; + } + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_fan_div(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + u8 tmp; + int old_div; + int new_min; + + tmp = val == 8 ? 0xc0 : + val == 4 ? 0x80 : + val == 2 ? 0x40 : + val == 1 ? 0x00 : + 0xff; + if (tmp == 0xff) + return -EINVAL; + + down(&data->update_lock); + old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); + data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); + new_min = data->fan_min[nr] * old_div / + FAN_DIV_FROM_REG(data->fan_div[nr]); + data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; + data->fan[nr] = data->fan[nr] * old_div / + FAN_DIV_FROM_REG(data->fan_div[nr]); + + adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), + data->fan_div[nr]); + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_div, set_fan_##offset##_div); \ +static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset) + +fan_offset(1); +fan_offset(2); + + +/* Temps */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + int ext; + ext = nr == 0 ? + ((data->ext_temp[nr] >> 6) & 0x3) * 2 : + (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); + return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); +} +static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); +} +static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); +} +static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); +} +static ssize_t +set_temp_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), + data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_temp_max(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), + data->temp_max[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_crit[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), + data->temp_crit[nr]); + up(&data->update_lock); + return count; +} + +#define temp_reg(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_crit(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_max(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_crit(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ + NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_min, set_temp_##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_max, set_temp_##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_crit, set_temp_##offset##_crit) + +temp_reg(1); +temp_reg(2); +temp_reg(3); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", data->alarm); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +static int adm1031_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1031_detect); +} + +/* This function is called by i2c_detect */ +static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm1031_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm1031_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1031_driver; + new_client->flags = 0; + + if (kind < 0) { + int id, co; + id = i2c_smbus_read_byte_data(new_client, 0x3d); + co = i2c_smbus_read_byte_data(new_client, 0x3e); + + if (!((id == 0x31 || id == 0x30) && co == 0x41)) + goto exit_free; + kind = (id == 0x30) ? adm1030 : adm1031; + } + + if (kind <= 0) + kind = adm1031; + + /* Given the detected chip type, set the chip name and the + * auto fan control helper table. */ + if (kind == adm1030) { + name = "adm1030"; + data->chan_select_table = &auto_channel_select_table_adm1030; + } else if (kind == adm1031) { + name = "adm1031"; + data->chan_select_table = &auto_channel_select_table_adm1031; + } + data->chip_type = kind; + + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the ADM1031 chip */ + adm1031_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + + device_create_file(&new_client->dev, &dev_attr_auto_temp1_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp1_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp1_max); + + device_create_file(&new_client->dev, &dev_attr_auto_temp2_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp2_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp2_max); + + device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + if (kind == adm1031) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, + &dev_attr_auto_fan2_channel); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_max); + device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm); + } + + return 0; + +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm1031_detach_client(struct i2c_client *client) +{ + int ret; + if ((ret = i2c_detach_client(client)) != 0) { + return ret; + } + kfree(client); + return 0; +} + +static void adm1031_init_client(struct i2c_client *client) +{ + unsigned int read_val; + unsigned int mask; + struct adm1031_data *data = i2c_get_clientdata(client); + + mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); + if (data->chip_type == adm1031) { + mask |= (ADM1031_CONF2_PWM2_ENABLE | + ADM1031_CONF2_TACH2_ENABLE); + } + /* Initialize the ADM1031 chip (enables fan speed reading ) */ + read_val = adm1031_read_value(client, ADM1031_REG_CONF2); + if ((read_val | mask) != read_val) { + adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); + } + + read_val = adm1031_read_value(client, ADM1031_REG_CONF1); + if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { + adm1031_write_value(client, ADM1031_REG_CONF1, read_val | + ADM1031_CONF1_MONITOR_ENABLE); + } + +} + +static struct adm1031_data *adm1031_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int chan; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting adm1031 update\n"); + for (chan = 0; + chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { + u8 oldh, newh; + + oldh = + adm1031_read_value(client, ADM1031_REG_TEMP(chan)); + data->ext_temp[chan] = + adm1031_read_value(client, ADM1031_REG_EXT_TEMP); + newh = + adm1031_read_value(client, ADM1031_REG_TEMP(chan)); + if (newh != oldh) { + data->ext_temp[chan] = + adm1031_read_value(client, + ADM1031_REG_EXT_TEMP); +#ifdef DEBUG + oldh = + adm1031_read_value(client, + ADM1031_REG_TEMP(chan)); + + /* oldh is actually newer */ + if (newh != oldh) + dev_warn(&client->dev, + "Remote temperature may be " + "wrong.\n"); +#endif + } + data->temp[chan] = newh; + + data->temp_min[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_MIN(chan)); + data->temp_max[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_MAX(chan)); + data->temp_crit[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_CRIT(chan)); + data->auto_temp[chan] = + adm1031_read_value(client, + ADM1031_REG_AUTO_TEMP(chan)); + + } + + data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); + data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); + + data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) + | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) + << 8); + if (data->chip_type == adm1030) { + data->alarm &= 0xc0ff; + } + + for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { + data->fan_div[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); + data->fan_min[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); + data->fan[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); + data->pwm[chan] = + 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> + (4*chan)); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1031_init(void) +{ + return i2c_add_driver(&adm1031_driver); +} + +static void __exit sensors_adm1031_exit(void) +{ + i2c_del_driver(&adm1031_driver); +} + +MODULE_AUTHOR("Alexandre d'Alton "); +MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm1031_init); +module_exit(sensors_adm1031_exit); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c new file mode 100644 index 00000000000..5c68e9c311a --- /dev/null +++ b/drivers/hwmon/adm9240.c @@ -0,0 +1,791 @@ +/* + * adm9240.c Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 1999 Frodo Looijaard + * Philip Edelbrock + * Copyright (C) 2003 Michiel Rook + * Copyright (C) 2005 Grant Coady with valuable + * guidance from Jean Delvare + * + * Driver supports Analog Devices ADM9240 + * Dallas Semiconductor DS1780 + * National Semiconductor LM81 + * + * ADM9240 is the reference, DS1780 and LM81 are register compatibles + * + * Voltage Six inputs are scaled by chip, VID also reported + * Temperature Chip temperature to 0.5'C, maximum and max_hysteris + * Fans 2 fans, low speed alarm, automatic fan clock divider + * Alarms 16-bit map of active alarms + * Analog Out 0..1250 mV output + * + * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * + * Test hardware: Intel SE440BX-2 desktop motherboard --Grant + * + * LM81 extended temp reading not implemented + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; + +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(adm9240, ds1780, lm81); + +/* ADM9240 registers */ +#define ADM9240_REG_MAN_ID 0x3e +#define ADM9240_REG_DIE_REV 0x3f +#define ADM9240_REG_CONFIG 0x40 + +#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ +#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ +#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) +#define ADM9240_REG_INT(nr) (0x41 + (nr)) +#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) +#define ADM9240_REG_TEMP 0x27 +#define ADM9240_REG_TEMP_HIGH 0x39 +#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_ANALOG_OUT 0x19 +#define ADM9240_REG_CHASSIS_CLEAR 0x46 +#define ADM9240_REG_VID_FAN_DIV 0x47 +#define ADM9240_REG_I2C_ADDR 0x48 +#define ADM9240_REG_VID4 0x49 +#define ADM9240_REG_TEMP_CONF 0x4b + +/* generalised scaling with integer rounding */ +static inline int SCALE(long val, int mul, int div) +{ + if (val < 0) + return (val * mul - div / 2) / div; + else + return (val * mul + div / 2) / div; +} + +/* adm9240 internally scales voltage measurements */ +static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; + +static inline unsigned int IN_FROM_REG(u8 reg, int n) +{ + return SCALE(reg, nom_mv[n], 192); +} + +static inline u8 IN_TO_REG(unsigned long val, int n) +{ + return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); +} + +/* temperature range: -40..125, 127 disables temperature alarm */ +static inline s8 TEMP_TO_REG(long val) +{ + return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); +} + +/* two fans, each with low fan speed limit */ +static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) +{ + if (!reg) /* error */ + return -1; + + if (reg == 255) + return 0; + + return SCALE(1350000, 1, reg * div); +} + +/* analog out 0..1250mV */ +static inline u8 AOUT_TO_REG(unsigned long val) +{ + return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); +} + +static inline unsigned int AOUT_FROM_REG(u8 reg) +{ + return SCALE(reg, 1250, 255); +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter); +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm9240_init_client(struct i2c_client *client); +static int adm9240_detach_client(struct i2c_client *client); +static struct adm9240_data *adm9240_update_device(struct device *dev); + +/* driver data */ +static struct i2c_driver adm9240_driver = { + .owner = THIS_MODULE, + .name = "adm9240", + .id = I2C_DRIVERID_ADM9240, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm9240_attach_adapter, + .detach_client = adm9240_detach_client, +}; + +/* per client data */ +struct adm9240_data { + enum chips type; + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated_measure; + unsigned long last_updated_config; + + u8 in[6]; /* ro in0_input */ + u8 in_max[6]; /* rw in0_max */ + u8 in_min[6]; /* rw in0_min */ + u8 fan[2]; /* ro fan1_input */ + u8 fan_min[2]; /* rw fan1_min */ + u8 fan_div[2]; /* rw fan1_div, read-only accessor */ + s16 temp; /* ro temp1_input, 9-bit sign-extended */ + s8 temp_high; /* rw temp1_max */ + s8 temp_hyst; /* rw temp1_max_hyst */ + u16 alarms; /* ro alarms */ + u8 aout; /* rw aout_output */ + u8 vid; /* ro vid */ + u8 vrm; /* -- vrm set on startup, no accessor */ +}; + +/* i2c byte read/write interface */ +static int adm9240_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/*** sysfs accessors ***/ + +/* temperature */ +#define show_temp(value, scale) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct adm9240_data *data = adm9240_update_device(dev); \ + return sprintf(buf, "%d\n", data->value * scale); \ +} +show_temp(temp_high, 1000); +show_temp(temp_hyst, 1000); +show_temp(temp, 500); /* 0.5'C per bit */ + +#define set_temp(value, reg) \ +static ssize_t set_##value(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm9240_data *data = adm9240_update_device(dev); \ + long temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm9240_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(temp_high, ADM9240_REG_TEMP_HIGH); +set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_high, set_temp_high); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); + +/* voltage */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t show_in##offset(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ +static ssize_t show_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t \ +set_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t \ +set_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); + +/* fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); +} + +/* write new fan div, callers must hold data->update_lock */ +static void adm9240_write_fan_div(struct i2c_client *client, int nr, + u8 fan_div) +{ + u8 reg, old, shift = (nr + 2) * 2; + + reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + old = (reg >> shift) & 3; + reg &= ~(3 << shift); + reg |= (fan_div << shift); + adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + dev_dbg(&client->dev, "fan%d clock divider changed from %u " + "to %u\n", nr + 1, 1 << old, 1 << fan_div); +} + +/* + * set fan speed low limit: + * + * - value is zero: disable fan speed low limit alarm + * + * - value is below fan speed measurement range: enable fan speed low + * limit alarm to be asserted while fan speed too slow to measure + * + * - otherwise: select fan clock divider to suit fan speed low limit, + * measurement code may adjust registers to ensure fan speed reading + */ +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + u8 new_div; + + down(&data->update_lock); + + if (!val) { + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; + + dev_dbg(&client->dev, "fan%u low limit set disabled\n", + nr + 1); + + } else if (val < 1350000 / (8 * 254)) { + new_div = 3; + data->fan_min[nr] = 254; + + dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", + nr + 1, FAN_FROM_REG(254, 1 << new_div)); + + } else { + unsigned int new_min = 1350000 / val; + + new_div = 0; + while (new_min > 192 && new_div < 3) { + new_div++; + new_min /= 2; + } + if (!new_min) /* keep > 0 */ + new_min++; + + data->fan_min[nr] = new_min; + + dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", + nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); + } + + if (new_div != data->fan_div[nr]) { + data->fan_div[nr] = new_div; + adm9240_write_fan_div(client, nr, new_div); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ +return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan_##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +/* alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* vid */ +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* analog output */ +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} + +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* chassis_clear */ +static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtol(buf, NULL, 10); + + if (val == 1) { + adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + } + return count; +} +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); + + +/*** sensor chip detect and driver install ***/ + +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm9240_data *data; + int err = 0; + const char *name = ""; + u8 man_id, die_rev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm9240_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm9240_driver; + new_client->flags = 0; + + if (kind == 0) { + kind = adm9240; + } + + if (kind < 0) { + + /* verify chip: reg address should match i2c address */ + if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + != address) { + dev_err(&adapter->dev, "detect fail: address match, " + "0x%02x\n", address); + goto exit_free; + } + + /* check known chip manufacturer */ + man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); + + if (man_id == 0x23) { + kind = adm9240; + } else if (man_id == 0xda) { + kind = ds1780; + } else if (man_id == 0x01) { + kind = lm81; + } else { + dev_err(&adapter->dev, "detect fail: unknown manuf, " + "0x%02x\n", man_id); + goto exit_free; + } + + /* successful detect, print chip info */ + die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + dev_info(&adapter->dev, "found %s revision %u\n", + man_id == 0x23 ? "ADM9240" : + man_id == 0xda ? "DS1780" : "LM81", die_rev); + } + + /* either forced or detected chip kind */ + if (kind == adm9240) { + name = "adm9240"; + } else if (kind == ds1780) { + name = "ds1780"; + } else if (kind == lm81) { + name = "lm81"; + } + + /* fill in the remaining client fields and attach */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + adm9240_init_client(new_client); + + /* populate sysfs filesystem */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + device_create_file(&new_client->dev, &dev_attr_chassis_clear); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm9240_detect); +} + +static int adm9240_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 void adm9240_init_client(struct i2c_client *client) +{ + struct adm9240_data *data = i2c_get_clientdata(client); + u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); + u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + + data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ + + dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, + data->vrm % 10); + + if (conf & 1) { /* measurement cycle running: report state */ + + dev_info(&client->dev, "status: config 0x%02x mode %u\n", + conf, mode); + + } else { /* cold start: open limits before starting chip */ + int i; + + for (i = 0; i < 6; i++) + { + adm9240_write_value(client, + ADM9240_REG_IN_MIN(i), 0); + adm9240_write_value(client, + ADM9240_REG_IN_MAX(i), 255); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); + adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); + adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); + adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + + /* start measurement cycle */ + adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + + dev_info(&client->dev, "cold start: config was 0x%02x " + "mode %u\n", conf, mode); + } +} + +static struct adm9240_data *adm9240_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + /* minimum measurement cycle: 1.75 seconds */ + if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) + || !data->valid) { + + for (i = 0; i < 6; i++) /* read voltages */ + { + data->in[i] = adm9240_read_value(client, + ADM9240_REG_IN(i)); + } + data->alarms = adm9240_read_value(client, + ADM9240_REG_INT(0)) | + adm9240_read_value(client, + ADM9240_REG_INT(1)) << 8; + + /* read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant */ + data->temp = ((adm9240_read_value(client, + ADM9240_REG_TEMP) << 8) | + adm9240_read_value(client, + ADM9240_REG_TEMP_CONF)) / 128; + + for (i = 0; i < 2; i++) /* read fans */ + { + data->fan[i] = adm9240_read_value(client, + ADM9240_REG_FAN(i)); + + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + adm9240_write_fan_div(client, i, + ++data->fan_div[i]); + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + data->last_updated_measure = jiffies; + } + + /* minimum config reading cycle: 300 seconds */ + if (time_after(jiffies, data->last_updated_config + (HZ * 300)) + || !data->valid) { + + for (i = 0; i < 6; i++) + { + data->in_min[i] = adm9240_read_value(client, + ADM9240_REG_IN_MIN(i)); + data->in_max[i] = adm9240_read_value(client, + ADM9240_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) + { + data->fan_min[i] = adm9240_read_value(client, + ADM9240_REG_FAN_MIN(i)); + } + data->temp_high = adm9240_read_value(client, + ADM9240_REG_TEMP_HIGH); + data->temp_hyst = adm9240_read_value(client, + ADM9240_REG_TEMP_HYST); + + /* read fan divs and 5-bit VID */ + i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 3; + data->fan_div[1] = (i >> 6) & 3; + data->vid = i & 0x0f; + data->vid |= (adm9240_read_value(client, + ADM9240_REG_VID4) & 1) << 4; + /* read analog out */ + data->aout = adm9240_read_value(client, + ADM9240_REG_ANALOG_OUT); + + data->last_updated_config = jiffies; + data->valid = 1; + } + up(&data->update_lock); + return data; +} + +static int __init sensors_adm9240_init(void) +{ + return i2c_add_driver(&adm9240_driver); +} + +static void __exit sensors_adm9240_exit(void) +{ + i2c_del_driver(&adm9240_driver); +} + +MODULE_AUTHOR("Michiel Rook , " + "Grant Coady and others"); +MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm9240_init); +module_exit(sensors_adm9240_exit); + diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c new file mode 100644 index 00000000000..70d996d6fe0 --- /dev/null +++ b/drivers/hwmon/asb100.c @@ -0,0 +1,1065 @@ +/* + asb100.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (C) 2004 Mark M. Hoffman + + (derived from w83781d.c) + + Copyright (C) 1998 - 2003 Frodo Looijaard , + Philip Edelbrock , and + Mark Studebaker + + 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. +*/ + +/* + This driver supports the hardware sensor chips: Asus ASB100 and + ASB100-A "BACH". + + ASB100-A supports pwm1, while plain ASB100 does not. There is no known + way for the driver to tell which one is there. + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + asb100 7 3 1 4 0x31 0x0694 yes no +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* + HISTORY: + 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6 +*/ +#define ASB100_VERSION "1.0.0" + +/* I2C addresses to scan */ +static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; + +/* ISA addresses to scan (none) */ +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(asb100); +I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + +/* Voltage IN registers 0-6 */ +#define ASB100_REG_IN(nr) (0x20 + (nr)) +#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) +#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) + +/* FAN IN registers 1-3 */ +#define ASB100_REG_FAN(nr) (0x28 + (nr)) +#define ASB100_REG_FAN_MIN(nr) (0x3b + (nr)) + +/* TEMPERATURE registers 1-4 */ +static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; +static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; +static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; + +#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) +#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) +#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) + +#define ASB100_REG_TEMP2_CONFIG 0x0152 +#define ASB100_REG_TEMP3_CONFIG 0x0252 + + +#define ASB100_REG_CONFIG 0x40 +#define ASB100_REG_ALARM1 0x41 +#define ASB100_REG_ALARM2 0x42 +#define ASB100_REG_SMIM1 0x43 +#define ASB100_REG_SMIM2 0x44 +#define ASB100_REG_VID_FANDIV 0x47 +#define ASB100_REG_I2C_ADDR 0x48 +#define ASB100_REG_CHIPID 0x49 +#define ASB100_REG_I2C_SUBADDR 0x4a +#define ASB100_REG_PIN 0x4b +#define ASB100_REG_IRQ 0x4c +#define ASB100_REG_BANK 0x4e +#define ASB100_REG_CHIPMAN 0x4f + +#define ASB100_REG_WCHIPID 0x58 + +/* bit 7 -> enable, bits 0-3 -> duty cycle */ +#define ASB100_REG_PWM1 0x59 + +/* CONVERSIONS + Rounding and limit checking is only done on the TO_REG variants. */ + +/* These constants are a guess, consistent w/ w83781d */ +#define ASB100_IN_MIN ( 0) +#define ASB100_IN_MAX (4080) + +/* IN: 1/1000 V (0V to 4.08V) + REG: 16mV/bit */ +static u8 IN_TO_REG(unsigned val) +{ + unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); + return (nval + 8) / 16; +} + +static unsigned IN_FROM_REG(u8 reg) +{ + return reg * 16; +} + +static u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == -1) + return 0; + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* These constants are a guess, consistent w/ w83781d */ +#define ASB100_TEMP_MIN (-128000) +#define ASB100_TEMP_MAX ( 127000) + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static u8 TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); + ntemp += (ntemp<0 ? -500 : 500); + return (u8)(ntemp / 1000); +} + +static int TEMP_FROM_REG(u8 reg) +{ + return (s8)reg * 1000; +} + +/* PWM: 0 - 255 per sensors documentation + REG: (6.25% duty cycle per bit) */ +static u8 ASB100_PWM_TO_REG(int pwm) +{ + pwm = SENSORS_LIMIT(pwm, 0, 255); + return (u8)(pwm / 16); +} + +static int ASB100_PWM_FROM_REG(u8 reg) +{ + return reg * 16; +} + +#define DIV_FROM_REG(val) (1 << (val)) + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static u8 DIV_TO_REG(long val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} + +/* For each registered client, we need to keep some data in memory. That + data is pointed to by client->data. The structure itself is + dynamically allocated, at the same time the client itself is allocated. */ +struct asb100_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + /* array of 2 pointers to subclients */ + struct i2c_client *lm75[2]; + + char valid; /* !=0 if following fields are valid */ + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u16 temp[4]; /* Register value (0 and 3 are u8 only) */ + u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ + u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ + u8 fan_div[3]; /* Register encoding, right justified */ + u8 pwm; /* Register encoding */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u8 vrm; +}; + +static int asb100_read_value(struct i2c_client *client, u16 reg); +static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); + +static int asb100_attach_adapter(struct i2c_adapter *adapter); +static int asb100_detect(struct i2c_adapter *adapter, int address, int kind); +static int asb100_detach_client(struct i2c_client *client); +static struct asb100_data *asb100_update_device(struct device *dev); +static void asb100_init_client(struct i2c_client *client); + +static struct i2c_driver asb100_driver = { + .owner = THIS_MODULE, + .name = "asb100", + .id = I2C_DRIVERID_ASB100, + .flags = I2C_DF_NOTIFY, + .attach_adapter = asb100_attach_adapter, + .detach_client = asb100_detach_client, +}; + +/* 7 Voltages */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct asb100_data *data = asb100_update_device(dev); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ +} + +show_in_reg(in) +show_in_reg(in_min) +show_in_reg(in_max) + +#define set_in_reg(REG, reg) \ +static ssize_t set_in_##reg(struct device *dev, const char *buf, \ + size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + asb100_write_value(client, ASB100_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} + +set_in_reg(MIN, min) +set_in_reg(MAX, max) + +#define sysfs_in(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +sysfs_in(0); +sysfs_in(1); +sysfs_in(2); +sysfs_in(3); +sysfs_in(4); +sysfs_in(5); +sysfs_in(6); + +#define device_create_file_in(client, offset) do { \ + device_create_file(&client->dev, &dev_attr_in##offset##_input); \ + device_create_file(&client->dev, &dev_attr_in##offset##_min); \ + device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long min; + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + + down(&data->update_lock); + + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + data->fan_div[nr] = DIV_TO_REG(val); + + switch(nr) { + case 0: /* fan 1 */ + reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); + reg = (reg & 0xcf) | (data->fan_div[0] << 4); + asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); + break; + + case 1: /* fan 2 */ + reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); + reg = (reg & 0x3f) | (data->fan_div[1] << 6); + asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); + break; + + case 2: /* fan 3 */ + reg = asb100_read_value(client, ASB100_REG_PIN); + reg = (reg & 0x3f) | (data->fan_div[2] << 6); + asb100_write_value(client, ASB100_REG_PIN, reg); + break; + } + + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); + + up(&data->update_lock); + + return count; +} + +#define sysfs_fan(offset) \ +static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan##offset##_div, set_fan##offset##_div); + +sysfs_fan(1); +sysfs_fan(2); +sysfs_fan(3); + +#define device_create_file_fan(client, offset) do { \ + device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +/* 4 Temp. Sensors */ +static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) +{ + int ret = 0; + + switch (nr) { + case 1: case 2: + ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg)); + break; + case 0: case 3: default: + ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg)); + break; + } + return ret; +} + +#define show_temp_reg(reg) \ +static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct asb100_data *data = asb100_update_device(dev); \ + return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ +} + +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_hyst); + +#define set_temp_reg(REG, reg) \ +static ssize_t set_##reg(struct device *dev, const char *buf, \ + size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + switch (nr) { \ + case 1: case 2: \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + break; \ + case 0: case 3: default: \ + data->reg[nr] = TEMP_TO_REG(val); \ + break; \ + } \ + asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp_reg(MAX, temp_max); +set_temp_reg(HYST, temp_hyst); + +#define sysfs_temp(num) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ +static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, num-1); \ +} \ +static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_temp_max(dev, buf, count, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ + show_temp_max##num, set_temp_max##num); \ +static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_hyst(dev, buf, num-1); \ +} \ +static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_temp_hyst(dev, buf, count, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_hyst##num, set_temp_hyst##num); + +sysfs_temp(1); +sysfs_temp(2); +sysfs_temp(3); +sysfs_temp(4); + +/* VID */ +#define device_create_file_temp(client, num) do { \ + device_create_file(&client->dev, &dev_attr_temp##num##_input); \ + device_create_file(&client->dev, &dev_attr_temp##num##_max); \ + device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ +} while (0) + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} + +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +/* VRM */ +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", data->vrm); +} + +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + return count; +} + +/* Alarms */ +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms) + +/* 1 PWM */ +static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); +} + +static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm &= 0x80; /* keep the enable bit */ + data->pwm |= (0x0f & ASB100_PWM_TO_REG(val)); + asb100_write_value(client, ASB100_REG_PWM1, data->pwm); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); +} + +static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm &= 0x0f; /* keep the duty cycle bits */ + data->pwm |= (val ? 0x80 : 0x00); + asb100_write_value(client, ASB100_REG_PWM1, data->pwm); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); +static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + show_pwm_enable1, set_pwm_enable1); +#define device_create_file_pwm1(client) do { \ + device_create_file(&new_client->dev, &dev_attr_pwm1); \ + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \ +} while (0) + +/* This function is called when: + asb100_driver is inserted (when this module is loaded), for each + available adapter + when a new adapter is inserted (and asb100_driver is still present) + */ +static int asb100_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, asb100_detect); +} + +static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, + int kind, struct i2c_client *new_client) +{ + int i, id, err; + struct asb100_data *data = i2c_get_clientdata(new_client); + + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -ENODEV; + goto ERROR_SC_2; + } + } + asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) <<4)); + data->lm75[0]->addr = force_subclients[2]; + data->lm75[1]->addr = force_subclients[3]; + } else { + int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); + data->lm75[0]->addr = 0x48 + (val & 0x07); + data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); + } + + if(data->lm75[0]->addr == data->lm75[1]->addr) { + dev_err(&new_client->dev, "duplicate addresses 0x%x " + "for subclients\n", data->lm75[0]->addr); + err = -ENODEV; + goto ERROR_SC_2; + } + + for (i = 0; i <= 1; i++) { + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &asb100_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); + } + + if ((err = i2c_attach_client(data->lm75[0]))) { + dev_err(&new_client->dev, "subclient %d registration " + "at address 0x%x failed.\n", i, data->lm75[0]->addr); + goto ERROR_SC_2; + } + + if ((err = i2c_attach_client(data->lm75[1]))) { + dev_err(&new_client->dev, "subclient %d registration " + "at address 0x%x failed.\n", i, data->lm75[1]->addr); + goto ERROR_SC_3; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); +ERROR_SC_2: + kfree(data->lm75[1]); +ERROR_SC_1: + kfree(data->lm75[0]); +ERROR_SC_0: + return err; +} + +static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int err; + struct i2c_client *new_client; + struct asb100_data *data; + + /* asb100 is SMBus only */ + if (i2c_is_isa_adapter(adapter)) { + pr_debug("asb100.o: detect failed, " + "cannot attach to legacy adapter!\n"); + err = -ENODEV; + goto ERROR0; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pr_debug("asb100.o: detect failed, " + "smbus byte data not supported!\n"); + err = -ENODEV; + goto ERROR0; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access asb100_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { + pr_debug("asb100.o: detect failed, kmalloc failed!\n"); + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct asb100_data)); + + new_client = &data->client; + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &asb100_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + /* The chip may be stuck in some other bank than bank 0. This may + make reading other information impossible. Specify a force=... or + force_*=... parameter, and the chip will be reset to the right + bank. */ + if (kind < 0) { + + int val1 = asb100_read_value(new_client, ASB100_REG_BANK); + int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + + /* If we're in bank 0 */ + if ( (!(val1 & 0x07)) && + /* Check for ASB100 ID (low byte) */ + ( ((!(val1 & 0x80)) && (val2 != 0x94)) || + /* Check for ASB100 ID (high byte ) */ + ((val1 & 0x80) && (val2 != 0x06)) ) ) { + pr_debug("asb100.o: detect failed, " + "bad chip id 0x%02x!\n", val2); + err = -ENODEV; + goto ERROR1; + } + + } /* kind < 0 */ + + /* We have either had a force parameter, or we have already detected + Winbond. Put it now into bank 0 and Vendor ID High Byte */ + asb100_write_value(new_client, ASB100_REG_BANK, + (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); + int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + + if ((val1 == 0x31) && (val2 == 0x06)) + kind = asb100; + else { + if (kind == 0) + dev_warn(&new_client->dev, "ignoring " + "'force' parameter for unknown chip " + "at adapter %d, address 0x%02x.\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR1; + } + } + + /* Fill in remaining client fields and put it into the global list */ + strlcpy(new_client->name, "asb100", I2C_NAME_SIZE); + data->type = kind; + + 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 ERROR1; + + /* Attach secondary lm75 clients */ + if ((err = asb100_detect_subclients(adapter, address, kind, + new_client))) + goto ERROR2; + + /* Initialize the chip */ + asb100_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); + data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); + data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + device_create_file_temp(new_client, 4); + + device_create_file_vid(new_client); + device_create_file_vrm(new_client); + + device_create_file_alarms(new_client); + + device_create_file_pwm1(new_client); + + return 0; + +ERROR2: + i2c_detach_client(new_client); +ERROR1: + kfree(data); +ERROR0: + return err; +} + +static int asb100_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "client deregistration failed; " + "client not detached.\n"); + return err; + } + + if (i2c_get_clientdata(client)==NULL) { + /* subclients */ + kfree(client); + } else { + /* main client */ + kfree(i2c_get_clientdata(client)); + } + + return 0; +} + +/* The SMBus locks itself, usually, but nothing may access the chip between + bank switches. */ +static int asb100_read_value(struct i2c_client *client, u16 reg) +{ + struct asb100_data *data = i2c_get_clientdata(client); + struct i2c_client *cl; + int res, bank; + + down(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); + + if (bank == 0 || bank > 2) { + res = i2c_smbus_read_byte_data(client, reg & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x50: /* TEMP */ + res = swab16(i2c_smbus_read_word_data (cl, 0)); + break; + case 0x52: /* CONFIG */ + res = i2c_smbus_read_byte_data(cl, 1); + break; + case 0x53: /* HYST */ + res = swab16(i2c_smbus_read_word_data (cl, 2)); + break; + case 0x55: /* MAX */ + default: + res = swab16(i2c_smbus_read_word_data (cl, 3)); + break; + } + } + + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + + up(&data->lock); + + return res; +} + +static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct asb100_data *data = i2c_get_clientdata(client); + struct i2c_client *cl; + int bank; + + down(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); + + if (bank == 0 || bank > 2) { + i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x52: /* CONFIG */ + i2c_smbus_write_byte_data(cl, 1, value & 0xff); + break; + case 0x53: /* HYST */ + i2c_smbus_write_word_data(cl, 2, swab16(value)); + break; + case 0x55: /* MAX */ + i2c_smbus_write_word_data(cl, 3, swab16(value)); + break; + } + } + + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + + up(&data->lock); +} + +static void asb100_init_client(struct i2c_client *client) +{ + struct asb100_data *data = i2c_get_clientdata(client); + int vid = 0; + + vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; + vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; + data->vrm = i2c_which_vrm(); + vid = vid_from_reg(vid, data->vrm); + + /* Start monitoring */ + asb100_write_value(client, ASB100_REG_CONFIG, + (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); +} + +static struct asb100_data *asb100_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "starting device update...\n"); + + /* 7 voltage inputs */ + for (i = 0; i < 7; i++) { + data->in[i] = asb100_read_value(client, + ASB100_REG_IN(i)); + data->in_min[i] = asb100_read_value(client, + ASB100_REG_IN_MIN(i)); + data->in_max[i] = asb100_read_value(client, + ASB100_REG_IN_MAX(i)); + } + + /* 3 fan inputs */ + for (i = 0; i < 3; i++) { + data->fan[i] = asb100_read_value(client, + ASB100_REG_FAN(i)); + data->fan_min[i] = asb100_read_value(client, + ASB100_REG_FAN_MIN(i)); + } + + /* 4 temperature inputs */ + for (i = 1; i <= 4; i++) { + data->temp[i-1] = asb100_read_value(client, + ASB100_REG_TEMP(i)); + data->temp_max[i-1] = asb100_read_value(client, + ASB100_REG_TEMP_MAX(i)); + data->temp_hyst[i-1] = asb100_read_value(client, + ASB100_REG_TEMP_HYST(i)); + } + + /* VID and fan divisors */ + i = asb100_read_value(client, ASB100_REG_VID_FANDIV); + data->vid = i & 0x0f; + data->vid |= (asb100_read_value(client, + ASB100_REG_CHIPID) & 0x01) << 4; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->fan_div[2] = (asb100_read_value(client, + ASB100_REG_PIN) >> 6) & 0x03; + + /* PWM */ + data->pwm = asb100_read_value(client, ASB100_REG_PWM1); + + /* alarms */ + data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + + (asb100_read_value(client, ASB100_REG_ALARM2) << 8); + + data->last_updated = jiffies; + data->valid = 1; + + dev_dbg(&client->dev, "... device update complete\n"); + } + + up(&data->update_lock); + + return data; +} + +static int __init asb100_init(void) +{ + return i2c_add_driver(&asb100_driver); +} + +static void __exit asb100_exit(void) +{ + i2c_del_driver(&asb100_driver); +} + +MODULE_AUTHOR("Mark M. Hoffman "); +MODULE_DESCRIPTION("ASB100 Bach driver"); +MODULE_LICENSE("GPL"); + +module_init(asb100_init); +module_exit(asb100_exit); + diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c new file mode 100644 index 00000000000..0bcf82b4c07 --- /dev/null +++ b/drivers/hwmon/atxp1.c @@ -0,0 +1,361 @@ +/* + atxp1.c - kernel module for setting CPU VID and general purpose + I/Os using the Attansic ATXP1 chip. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); +MODULE_VERSION("0.6.2"); +MODULE_AUTHOR("Sebastian Witt "); + +#define ATXP1_VID 0x00 +#define ATXP1_CVID 0x01 +#define ATXP1_GPIO1 0x06 +#define ATXP1_GPIO2 0x0a +#define ATXP1_VIDENA 0x20 +#define ATXP1_VIDMASK 0x1f +#define ATXP1_GPIO1MASK 0x0f + +static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +SENSORS_INSMOD_1(atxp1); + +static int atxp1_attach_adapter(struct i2c_adapter * adapter); +static int atxp1_detach_client(struct i2c_client * client); +static struct atxp1_data * atxp1_update_device(struct device *dev); +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); + +static struct i2c_driver atxp1_driver = { + .owner = THIS_MODULE, + .name = "atxp1", + .flags = I2C_DF_NOTIFY, + .attach_adapter = atxp1_attach_adapter, + .detach_client = atxp1_detach_client, +}; + +struct atxp1_data { + struct i2c_client client; + struct semaphore update_lock; + unsigned long last_updated; + u8 valid; + struct { + u8 vid; /* VID output register */ + u8 cpu_vid; /* VID input from CPU */ + u8 gpio1; /* General purpose I/O register 1 */ + u8 gpio2; /* General purpose I/O register 2 */ + } reg; + u8 vrm; /* Detected CPU VRM */ +}; + +static struct atxp1_data * atxp1_update_device(struct device *dev) +{ + struct i2c_client *client; + struct atxp1_data *data; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ) || + (jiffies < data->last_updated) || + !data->valid) { + + /* Update local register data */ + data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); + data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); + data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); + data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); + + data->valid = 1; + } + + up(&data->update_lock); + + return(data); +} + +/* sys file functions for cpu0_vid */ +static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); + + return size; +} + +static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + char vid; + char cvid; + unsigned int vcore; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + vcore = simple_strtoul(buf, NULL, 10); + vcore /= 25; + vcore *= 25; + + /* Calculate VID */ + vid = vid_to_reg(vcore, data->vrm); + + if (vid < 0) { + dev_err(dev, "VID calculation failed.\n"); + return -1; + } + + /* If output enabled, use control register value. Otherwise original CPU VID */ + if (data->reg.vid & ATXP1_VIDENA) + cvid = data->reg.vid & ATXP1_VIDMASK; + else + cvid = data->reg.cpu_vid; + + /* Nothing changed, aborting */ + if (vid == cvid) + return count; + + dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); + + /* Write every 25 mV step to increase stability */ + if (cvid > vid) { + for (; cvid >= vid; cvid--) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + else { + for (; cvid <= vid; cvid++) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + + data->valid = 0; + + return count; +} + +/* CPU core reference voltage + unit: millivolt +*/ +static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); + +/* sys file functions for GPIO1 */ +static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); + + return size; +} + +static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16); + + value &= ATXP1_GPIO1MASK; + + if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO1 data register + unit: Four bit as hex (e.g. 0x0f) +*/ +static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); + +/* sys file functions for GPIO2 */ +static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio2); + + return size; +} + +static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16) & 0xff; + + if (value != data->reg.gpio2) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO2 data register + unit: Eight bit as hex (e.g. 0xff) +*/ +static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); + + +static int atxp1_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, &atxp1_detect); +}; + +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client * new_client; + struct atxp1_data * data; + int err = 0; + u8 temp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct atxp1_data)); + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &atxp1_driver; + new_client->flags = 0; + + /* Detect ATXP1, checking if vendor ID registers are all zero */ + if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && + (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { + + /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) + * showing the same as register 0x00 */ + temp = i2c_smbus_read_byte_data(new_client, 0x00); + + if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && + (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) + goto exit_free; + } + + /* Get VRM */ + data->vrm = i2c_which_vrm(); + + if ((data->vrm != 90) && (data->vrm != 91)) { + dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", + data->vrm / 10, data->vrm % 10); + goto exit_free; + } + + strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); + + data->valid = 0; + + init_MUTEX(&data->update_lock); + + err = i2c_attach_client(new_client); + + if (err) + { + dev_err(&new_client->dev, "Attach client error.\n"); + goto exit_free; + } + + device_create_file(&new_client->dev, &dev_attr_gpio1); + device_create_file(&new_client->dev, &dev_attr_gpio2); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + dev_info(&new_client->dev, "Using VRM: %d.%d\n", + data->vrm / 10, data->vrm % 10); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +}; + +static int atxp1_detach_client(struct i2c_client * client) +{ + int err; + + err = i2c_detach_client(client); + + if (err) + dev_err(&client->dev, "Failed to detach client.\n"); + else + kfree(i2c_get_clientdata(client)); + + return err; +}; + +static int __init atxp1_init(void) +{ + return i2c_add_driver(&atxp1_driver); +}; + +static void __exit atxp1_exit(void) +{ + i2c_del_driver(&atxp1_driver); +}; + +module_init(atxp1_init); +module_exit(atxp1_exit); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c new file mode 100644 index 00000000000..5360d58804f --- /dev/null +++ b/drivers/hwmon/ds1621.c @@ -0,0 +1,341 @@ +/* + ds1621.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Christian W. Zuckschwerdt 2000-11-23 + based on lm75.c by Frodo Looijaard + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(ds1621); +static int polarity = -1; +module_param(polarity, int, 0); +MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); + +/* Many DS1621 constants specified below */ +/* Config register used for detection */ +/* 7 6 5 4 3 2 1 0 */ +/* |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 + +/* The DS1621 registers */ +#define DS1621_REG_TEMP 0xAA /* word, RO */ +#define DS1621_REG_TEMP_MIN 0xA1 /* word, RW */ +#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 +#define DS1621_ALARM_TEMP_LOW 0x20 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define ALARMS_FROM_REG(val) ((val) & \ + (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) + +/* Each client has this additional data */ +struct ds1621_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 temp, temp_min, temp_max; /* Register values, word */ + u8 conf; /* Register encoding, combined */ +}; + +static int ds1621_attach_adapter(struct i2c_adapter *adapter); +static int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind); +static void ds1621_init_client(struct i2c_client *client); +static int ds1621_detach_client(struct i2c_client *client); +static struct ds1621_data *ds1621_update_client(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver ds1621_driver = { + .owner = THIS_MODULE, + .name = "ds1621", + .id = I2C_DRIVERID_DS1621, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1621_attach_adapter, + .detach_client = ds1621_detach_client, +}; + +/* 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. */ +static int ds1621_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == DS1621_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +/* 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. */ +static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == DS1621_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void ds1621_init_client(struct i2c_client *client) +{ + int reg = ds1621_read_value(client, DS1621_REG_CONF); + /* switch to continuous conversion mode */ + reg &= ~ DS1621_REG_CONFIG_1SHOT; + + /* setup output polarity */ + if (polarity == 0) + reg &= ~DS1621_REG_CONFIG_POLARITY; + else if (polarity == 1) + reg |= DS1621_REG_CONFIG_POLARITY; + + ds1621_write_value(client, DS1621_REG_CONF, reg); + + /* start conversion */ + i2c_smbus_write_byte(client, DS1621_COM_START); +} + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct ds1621_data *data = ds1621_update_client(dev); \ + return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ +} + +show(temp); +show(temp_min); +show(temp_max); + +#define set_temp(suffix, value, reg) \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct ds1621_data *data = ds1621_update_client(dev); \ + u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ + \ + down(&data->update_lock); \ + data->value = val; \ + ds1621_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(min, temp_min, DS1621_REG_TEMP_MIN); +set_temp(max, temp_max, DS1621_REG_TEMP_MAX); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ds1621_data *data = ds1621_update_client(dev); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); + + +static int ds1621_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, ds1621_detect); +} + +/* This function is called by i2c_detect */ +int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int conf, temp; + struct i2c_client *new_client; + struct ds1621_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA + | I2C_FUNC_SMBUS_WRITE_BYTE)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access ds1621_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct ds1621_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &ds1621_driver; + new_client->flags = 0; + + + /* 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_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; + temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN); + if (temp & 0x007f) + goto exit_free; + temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX); + if (temp & 0x007f) + goto exit_free; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = ds1621; + + /* Fill in remaining client fields and put it into the global list */ + strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the DS1621 chip */ + ds1621_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + exit_free: + kfree(data); + exit: + return err; +} + +static int ds1621_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 struct ds1621_data *ds1621_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1621_data *data = i2c_get_clientdata(client); + u8 new_conf; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting ds1621 update\n"); + + data->conf = ds1621_read_value(client, DS1621_REG_CONF); + + data->temp = ds1621_read_value(client, DS1621_REG_TEMP); + + data->temp_min = ds1621_read_value(client, + DS1621_REG_TEMP_MIN); + data->temp_max = ds1621_read_value(client, + DS1621_REG_TEMP_MAX); + + /* reset alarms if necessary */ + new_conf = data->conf; + if (data->temp < data->temp_min) + new_conf &= ~DS1621_ALARM_TEMP_LOW; + if (data->temp > data->temp_max) + new_conf &= ~DS1621_ALARM_TEMP_HIGH; + if (data->conf != new_conf) + ds1621_write_value(client, DS1621_REG_CONF, + new_conf); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init ds1621_init(void) +{ + return i2c_add_driver(&ds1621_driver); +} + +static void __exit ds1621_exit(void) +{ + i2c_del_driver(&ds1621_driver); +} + + +MODULE_AUTHOR("Christian W. Zuckschwerdt "); +MODULE_DESCRIPTION("DS1621 driver"); +MODULE_LICENSE("GPL"); + +module_init(ds1621_init); +module_exit(ds1621_exit); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c new file mode 100644 index 00000000000..da411741c2c --- /dev/null +++ b/drivers/hwmon/fscher.c @@ -0,0 +1,691 @@ +/* + * fscher.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003, 2004 Reinhard Nissl + * + * 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 hermes chip, + * module based on fscpos.c + * Copyright (C) 2000 Hermann Jung + * Copyright (C) 1998, 1999 Frodo Looijaard + * and Philip Edelbrock + */ + +#include +#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(fscher); + +/* + * The FSCHER registers + */ + +/* chip identification */ +#define FSCHER_REG_IDENT_0 0x00 +#define FSCHER_REG_IDENT_1 0x01 +#define FSCHER_REG_IDENT_2 0x02 +#define FSCHER_REG_REVISION 0x03 + +/* global control and status */ +#define FSCHER_REG_EVENT_STATE 0x04 +#define FSCHER_REG_CONTROL 0x05 + +/* watchdog */ +#define FSCHER_REG_WDOG_PRESET 0x28 +#define FSCHER_REG_WDOG_STATE 0x23 +#define FSCHER_REG_WDOG_CONTROL 0x21 + +/* fan 0 */ +#define FSCHER_REG_FAN0_MIN 0x55 +#define FSCHER_REG_FAN0_ACT 0x0e +#define FSCHER_REG_FAN0_STATE 0x0d +#define FSCHER_REG_FAN0_RIPPLE 0x0f + +/* fan 1 */ +#define FSCHER_REG_FAN1_MIN 0x65 +#define FSCHER_REG_FAN1_ACT 0x6b +#define FSCHER_REG_FAN1_STATE 0x62 +#define FSCHER_REG_FAN1_RIPPLE 0x6f + +/* fan 2 */ +#define FSCHER_REG_FAN2_MIN 0xb5 +#define FSCHER_REG_FAN2_ACT 0xbb +#define FSCHER_REG_FAN2_STATE 0xb2 +#define FSCHER_REG_FAN2_RIPPLE 0xbf + +/* voltage supervision */ +#define FSCHER_REG_VOLT_12 0x45 +#define FSCHER_REG_VOLT_5 0x42 +#define FSCHER_REG_VOLT_BATT 0x48 + +/* temperature 0 */ +#define FSCHER_REG_TEMP0_ACT 0x64 +#define FSCHER_REG_TEMP0_STATE 0x71 + +/* temperature 1 */ +#define FSCHER_REG_TEMP1_ACT 0x32 +#define FSCHER_REG_TEMP1_STATE 0x81 + +/* temperature 2 */ +#define FSCHER_REG_TEMP2_ACT 0x35 +#define FSCHER_REG_TEMP2_STATE 0x91 + +/* + * Functions declaration + */ + +static int fscher_attach_adapter(struct i2c_adapter *adapter); +static int fscher_detect(struct i2c_adapter *adapter, int address, int kind); +static int fscher_detach_client(struct i2c_client *client); +static struct fscher_data *fscher_update_device(struct device *dev); +static void fscher_init_client(struct i2c_client *client); + +static int fscher_read_value(struct i2c_client *client, u8 reg); +static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver fscher_driver = { + .owner = THIS_MODULE, + .name = "fscher", + .id = I2C_DRIVERID_FSCHER, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscher_attach_adapter, + .detach_client = fscher_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct fscher_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero 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 watchdog[3]; /* watchdog */ + u8 volt[3]; /* 12, 5, battery voltage */ + 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 fan_min[3]; /* fan min value for rps */ + u8 fan_ripple[3]; /* divider for rps */ +}; + +/* + * Sysfs stuff + */ + +#define sysfs_r(kind, sub, offset, reg) \ +static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \ +static ssize_t show_##kind##offset##sub (struct device *, struct device_attribute *attr, char *); \ +static ssize_t show_##kind##offset##sub (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct fscher_data *data = fscher_update_device(dev); \ + return show_##kind##sub(data, buf, (offset)); \ +} + +#define sysfs_w(kind, sub, offset, reg) \ +static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \ +static ssize_t set_##kind##offset##sub (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscher_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, (offset), reg); \ +} + +#define sysfs_rw_n(kind, sub, offset, reg) \ +sysfs_r(kind, sub, offset, reg) \ +sysfs_w(kind, sub, offset, reg) \ +static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, show_##kind##offset##sub, set_##kind##offset##sub); + +#define sysfs_rw(kind, sub, reg) \ +sysfs_r(kind, sub, 0, reg) \ +sysfs_w(kind, sub, 0, reg) \ +static DEVICE_ATTR(kind##sub, S_IRUGO | S_IWUSR, show_##kind##0##sub, set_##kind##0##sub); + +#define sysfs_ro_n(kind, sub, offset, reg) \ +sysfs_r(kind, sub, offset, reg) \ +static DEVICE_ATTR(kind##offset##sub, S_IRUGO, show_##kind##offset##sub, NULL); + +#define sysfs_ro(kind, sub, reg) \ +sysfs_r(kind, sub, 0, reg) \ +static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0##sub, NULL); + +#define sysfs_fan(offset, reg_status, reg_min, reg_ripple, reg_act) \ +sysfs_rw_n(pwm, , offset, reg_min) \ +sysfs_rw_n(fan, _status, offset, reg_status) \ +sysfs_rw_n(fan, _div , offset, reg_ripple) \ +sysfs_ro_n(fan, _input , offset, reg_act) + +#define sysfs_temp(offset, reg_status, reg_act) \ +sysfs_rw_n(temp, _status, offset, reg_status) \ +sysfs_ro_n(temp, _input , offset, reg_act) + +#define sysfs_in(offset, reg_act) \ +sysfs_ro_n(in, _input, offset, reg_act) + +#define sysfs_revision(reg_revision) \ +sysfs_ro(revision, , reg_revision) + +#define sysfs_alarms(reg_events) \ +sysfs_ro(alarms, , reg_events) + +#define sysfs_control(reg_control) \ +sysfs_rw(control, , reg_control) + +#define sysfs_watchdog(reg_control, reg_status, reg_preset) \ +sysfs_rw(watchdog, _control, reg_control) \ +sysfs_rw(watchdog, _status , reg_status) \ +sysfs_rw(watchdog, _preset , reg_preset) + +sysfs_fan(1, FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_MIN, + FSCHER_REG_FAN0_RIPPLE, FSCHER_REG_FAN0_ACT) +sysfs_fan(2, FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_MIN, + FSCHER_REG_FAN1_RIPPLE, FSCHER_REG_FAN1_ACT) +sysfs_fan(3, FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_MIN, + FSCHER_REG_FAN2_RIPPLE, FSCHER_REG_FAN2_ACT) + +sysfs_temp(1, FSCHER_REG_TEMP0_STATE, FSCHER_REG_TEMP0_ACT) +sysfs_temp(2, FSCHER_REG_TEMP1_STATE, FSCHER_REG_TEMP1_ACT) +sysfs_temp(3, FSCHER_REG_TEMP2_STATE, FSCHER_REG_TEMP2_ACT) + +sysfs_in(0, FSCHER_REG_VOLT_12) +sysfs_in(1, FSCHER_REG_VOLT_5) +sysfs_in(2, FSCHER_REG_VOLT_BATT) + +sysfs_revision(FSCHER_REG_REVISION) +sysfs_alarms(FSCHER_REG_EVENTS) +sysfs_control(FSCHER_REG_CONTROL) +sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET) + +#define device_create_file_fan(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_fan##offset##_status); \ + device_create_file(&client->dev, &dev_attr_pwm##offset); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +} while (0) + +#define device_create_file_temp(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_temp##offset##_status); \ + device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +} while (0) + +#define device_create_file_in(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +} while (0) + +#define device_create_file_revision(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_revision); \ +} while (0) + +#define device_create_file_alarms(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_alarms); \ +} while (0) + +#define device_create_file_control(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_control); \ +} while (0) + +#define device_create_file_watchdog(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_watchdog_status); \ + device_create_file(&client->dev, &dev_attr_watchdog_control); \ + device_create_file(&client->dev, &dev_attr_watchdog_preset); \ +} while (0) + +/* + * Real code + */ + +static int fscher_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, fscher_detect); +} + +static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct fscher_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 i2c_smbus_read_byte_data. */ + if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct fscher_data)); + + /* The common I2C client data is placed right before the + * Hermes-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &fscher_driver; + new_client->flags = 0; + + /* Do the remaining detection unless force or force_fscher parameter */ + if (kind < 0) { + if ((i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ + || (i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ + || (i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */ + goto exit_free; + } + + /* Fill in the remaining client fields and put it into the + * global list */ + strlcpy(new_client->name, "fscher", 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; + + fscher_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file_revision(new_client); + device_create_file_alarms(new_client); + device_create_file_control(new_client); + device_create_file_watchdog(new_client); + + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int fscher_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 fscher_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 fscher_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 FSC Hermes. */ +static void fscher_init_client(struct i2c_client *client) +{ + struct fscher_data *data = i2c_get_clientdata(client); + + /* Read revision from chip */ + data->revision = fscher_read_value(client, FSCHER_REG_REVISION); +} + +static struct fscher_data *fscher_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fscher_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + + dev_dbg(&client->dev, "Starting fscher update\n"); + + data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); + data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); + data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); + data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); + data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); + data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); + + data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); + data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); + data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); + + data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); + data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); + data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); + data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); + data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); + data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); + data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); + data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); + data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); + data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); + data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); + data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); + + data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); + data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); + data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); + + data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + + + +#define FAN_INDEX_FROM_NUM(nr) ((nr) - 1) + +static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; + + down(&data->update_lock); + data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04); +} + +static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v; + fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]); +} + +static ssize_t set_fan_div(struct i2c_client *client, struct fscher_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_div value %ld not " + "supported. Choose one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + + /* bits 2..7 reserved => mask with 0x03 */ + data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03; + data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v; + + fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03)); +} + +#define RPM_FROM_REG(val) (val*60) + +static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)])); +} + + + +#define TEMP_INDEX_FROM_NUM(nr) ((nr) - 1) + +static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 2..7 reserved, 0 read only => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + down(&data->update_lock); + data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03); +} + +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)])); +} + +/* + * The final conversion is specified in sensors.conf, as it depends on + * mainboard specific values. We export the registers contents as + * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much + * sense per se, but it minimizes the conversions count and keeps the + * values within a usual range. + */ +#define VOLT_FROM_REG(val) ((val) * 10) + +static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr])); +} + + + +static ssize_t show_revision(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->revision); +} + + + +static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2, 5..6 reserved => mask with 0x9b */ + return sprintf(buf, "%u\n", data->global_event & 0x9b); +} + + + +static ssize_t set_control(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 1..7 reserved => mask with 0x01 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; + + down(&data->update_lock); + data->global_control &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_control(struct fscher_data *data, char *buf, int nr) +{ + /* bits 1..7 reserved => mask with 0x01 */ + return sprintf(buf, "%u\n", data->global_control & 0x01); +} + + + +static ssize_t set_watchdog_control(struct i2c_client *client, struct + fscher_data *data, const char *buf, size_t count, + int nr, int reg) +{ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + + down(&data->update_lock); + data->watchdog[2] &= ~0xf0; + data->watchdog[2] |= v; + fscher_write_value(client, reg, data->watchdog[2]); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */ + return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0); +} + +static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + down(&data->update_lock); + data->watchdog[1] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + return sprintf(buf, "%u\n", data->watchdog[1] & 0x02); +} + +static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + + down(&data->update_lock); + data->watchdog[0] = v; + fscher_write_value(client, reg, data->watchdog[0]); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->watchdog[0]); +} + +static int __init sensors_fscher_init(void) +{ + return i2c_add_driver(&fscher_driver); +} + +static void __exit sensors_fscher_exit(void) +{ + i2c_del_driver(&fscher_driver); +} + +MODULE_AUTHOR("Reinhard Nissl "); +MODULE_DESCRIPTION("FSC Hermes driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_fscher_init); +module_exit(sensors_fscher_exit); diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c new file mode 100644 index 00000000000..3beaa6191ef --- /dev/null +++ b/drivers/hwmon/fscpos.c @@ -0,0 +1,641 @@ +/* + 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; + } + + down(&data->update_lock); + /* 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]); + up(&data->update_lock); + 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; + + down(&data->update_lock); + data->pwm[nr - 1] = v; + fscpos_write_value(client, reg, data->pwm[nr - 1]); + up(&data->update_lock); + 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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; + + down(&data->update_lock); + data->wdog_control &= ~0xf0; + data->wdog_control |= v; + fscpos_write_value(client, reg, data->wdog_control); + up(&data->update_lock); + 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; + } + + down(&data->update_lock); + data->wdog_state &= ~v; + fscpos_write_value(client, reg, v); + up(&data->update_lock); + 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) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + + down(&data->update_lock); + data->wdog_preset = v; + fscpos_write_value(client, reg, data->wdog_preset); + up(&data->update_lock); + return count; +} + +/* Event */ +static ssize_t show_event(struct device *dev, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, \ + 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 --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c new file mode 100644 index 00000000000..6bedf729dcf --- /dev/null +++ b/drivers/hwmon/gl518sm.c @@ -0,0 +1,604 @@ +/* + * gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 1998, 1999 Frodo Looijaard and + * Kyosti Malkki + * Copyright (C) 2004 Hong-Gunn Chew and + * Jean Delvare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Ported to Linux 2.6 by Hong-Gunn Chew with the help of Jean Delvare + * and advice of Greg Kroah-Hartman. + * + * Notes about the port: + * Release 0x00 of the GL518SM chipset doesn't support reading of in0, + * in1 nor in2. The original driver had an ugly workaround to get them + * anyway (changing limits and watching alarms trigger and wear off). + * We did not keep that part of the original driver in the Linux 2.6 + * version, since it was making the driver significantly more complex + * with no real benefit. + * + * History: + * 2004-01-28 Original port. (Hong-Gunn Chew) + * 2004-01-31 Code review and approval. (Jean Delvare) + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); + +/* Many GL518 constants specified below */ + +/* The GL518 registers */ +#define GL518_REG_CHIP_ID 0x00 +#define GL518_REG_REVISION 0x01 +#define GL518_REG_VENDOR_ID 0x02 +#define GL518_REG_CONF 0x03 +#define GL518_REG_TEMP_IN 0x04 +#define GL518_REG_TEMP_MAX 0x05 +#define GL518_REG_TEMP_HYST 0x06 +#define GL518_REG_FAN_COUNT 0x07 +#define GL518_REG_FAN_LIMIT 0x08 +#define GL518_REG_VIN1_LIMIT 0x09 +#define GL518_REG_VIN2_LIMIT 0x0a +#define GL518_REG_VIN3_LIMIT 0x0b +#define GL518_REG_VDD_LIMIT 0x0c +#define GL518_REG_VIN3 0x0d +#define GL518_REG_MISC 0x0f +#define GL518_REG_ALARM 0x10 +#define GL518_REG_MASK 0x11 +#define GL518_REG_INT 0x12 +#define GL518_REG_VIN2 0x13 +#define GL518_REG_VIN1 0x14 +#define GL518_REG_VDD 0x15 + + +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + * Fixing this is just not worth it. + */ + +#define RAW_FROM_REG(val) val + +#define BOOL_FROM_REG(val) ((val)?0:1) +#define BOOL_TO_REG(val) ((val)?0:1) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \ + (val)-500:(val)+500)/1000)+119),0,255)) +#define TEMP_FROM_REG(val) (((val) - 119) * 1000) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + long rpmdiv; + if (rpm == 0) + return 0; + rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; + return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); +} +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) + +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) +#define IN_FROM_REG(val) ((val)*19) + +#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) +#define VDD_FROM_REG(val) (((val)*95+2)/4) + +#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) +#define DIV_FROM_REG(val) (1 << (val)) + +#define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) +#define BEEP_MASK_FROM_REG(val) ((val) & 0x7f) + +/* Each client has this additional data */ +struct gl518_data { + struct i2c_client client; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 voltage_in[4]; /* Register values; [0] = VDD */ + u8 voltage_min[4]; /* Register values; [0] = VDD */ + u8 voltage_max[4]; /* Register values; [0] = VDD */ + u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ + u8 fan_in[2]; + u8 fan_min[2]; + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 fan_auto1; /* Boolean */ + u8 temp_in; /* Register values */ + u8 temp_max; /* Register values */ + u8 temp_hyst; /* Register values */ + u8 alarms; /* Register value */ + u8 alarm_mask; /* Register value */ + u8 beep_mask; /* Register value */ + u8 beep_enable; /* Boolean */ +}; + +static int gl518_attach_adapter(struct i2c_adapter *adapter); +static int gl518_detect(struct i2c_adapter *adapter, int address, int kind); +static void gl518_init_client(struct i2c_client *client); +static int gl518_detach_client(struct i2c_client *client); +static int gl518_read_value(struct i2c_client *client, u8 reg); +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct gl518_data *gl518_update_device(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver gl518_driver = { + .owner = THIS_MODULE, + .name = "gl518sm", + .id = I2C_DRIVERID_GL518, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl518_attach_adapter, + .detach_client = gl518_detach_client, +}; + +/* + * Sysfs stuff + */ + +#define show(type, suffix, value) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl518_data *data = gl518_update_device(dev); \ + return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ +} + +#define show_fan(suffix, value, index) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl518_data *data = gl518_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ + DIV_FROM_REG(data->fan_div[index]))); \ +} + +show(TEMP, temp_input1, temp_in); +show(TEMP, temp_max1, temp_max); +show(TEMP, temp_hyst1, temp_hyst); +show(BOOL, fan_auto1, fan_auto1); +show_fan(fan_input1, fan_in, 0); +show_fan(fan_input2, fan_in, 1); +show_fan(fan_min1, fan_min, 0); +show_fan(fan_min2, fan_min, 1); +show(DIV, fan_div1, fan_div[0]); +show(DIV, fan_div2, fan_div[1]); +show(VDD, in_input0, voltage_in[0]); +show(IN, in_input1, voltage_in[1]); +show(IN, in_input2, voltage_in[2]); +show(IN, in_input3, voltage_in[3]); +show(VDD, in_min0, voltage_min[0]); +show(IN, in_min1, voltage_min[1]); +show(IN, in_min2, voltage_min[2]); +show(IN, in_min3, voltage_min[3]); +show(VDD, in_max0, voltage_max[0]); +show(IN, in_max1, voltage_max[1]); +show(IN, in_max2, voltage_max[2]); +show(IN, in_max3, voltage_max[3]); +show(RAW, alarms, alarms); +show(BOOL, beep_enable, beep_enable); +show(BEEP_MASK, beep_mask, beep_mask); + +#define set(type, suffix, value, reg) \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl518_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = type##_TO_REG(val); \ + gl518_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +#define set_bits(type, suffix, value, reg, mask, shift) \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl518_data *data = i2c_get_clientdata(client); \ + int regvalue; \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + regvalue = gl518_read_value(client, reg); \ + data->value = type##_TO_REG(val); \ + regvalue = (regvalue & ~mask) | (data->value << shift); \ + gl518_write_value(client, reg, regvalue); \ + up(&data->update_lock); \ + return count; \ +} + +#define set_low(type, suffix, value, reg) \ + set_bits(type, suffix, value, reg, 0x00ff, 0) +#define set_high(type, suffix, value, reg) \ + set_bits(type, suffix, value, reg, 0xff00, 8) + +set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); +set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); +set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); +set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); +set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); +set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); +set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); +set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); +set_low(IN, in_min3, voltage_min[3], GL518_REG_VIN3_LIMIT); +set_high(VDD, in_max0, voltage_max[0], GL518_REG_VDD_LIMIT); +set_high(IN, in_max1, voltage_max[1], GL518_REG_VIN1_LIMIT); +set_high(IN, in_max2, voltage_max[2], GL518_REG_VIN2_LIMIT); +set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); +set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); +set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); + +static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[0] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[0])); + regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); + gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); + + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (data->fan_min[0] == 0) + data->alarm_mask &= ~0x20; + else + data->alarm_mask |= 0x20; + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[1] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[1])); + regvalue = (regvalue & 0xff00) | data->fan_min[1]; + gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); + + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (data->fan_min[1] == 0) + data->alarm_mask &= ~0x40; + else + data->alarm_mask |= 0x40; + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, + show_temp_hyst1, set_temp_hyst1); +static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); +static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); +static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); +static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); +static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); +static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); +static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); +static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); +static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); +static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0); +static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1); +static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2); +static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3); +static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0); +static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1); +static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2); +static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, + show_beep_enable, set_beep_enable); +static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, + show_beep_mask, set_beep_mask); + +/* + * Real code + */ + +static int gl518_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, gl518_detect); +} + +static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct gl518_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access gl518_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct gl518_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &gl518_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) + || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) + goto exit_free; + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = gl518_read_value(new_client, GL518_REG_REVISION); + if (i == 0x00) { + kind = gl518sm_r00; + } else if (i == 0x80) { + kind = gl518sm_r80; + } else { + if (kind <= 0) + dev_info(&adapter->dev, + "Ignoring 'force' parameter for unknown " + "chip at adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + goto exit_free; + } + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the GL518SM chip */ + data->alarm_mask = 0xff; + data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; + gl518_init_client((struct i2c_client *) new_client); + + /* Register sysfs hooks */ + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_fan1_auto); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_beep_enable); + device_create_file(&new_client->dev, &dev_attr_beep_mask); + + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + +exit_free: + kfree(data); +exit: + return err; +} + + +/* Called when we have found a new GL518SM. + Note that we preserve D4:NoFan2 and D2:beep_enable. */ +static void gl518_init_client(struct i2c_client *client) +{ + /* Make sure we leave D7:Reset untouched */ + u8 regvalue = gl518_read_value(client, GL518_REG_CONF) & 0x7f; + + /* Comparator mode (D3=0), standby mode (D6=0) */ + gl518_write_value(client, GL518_REG_CONF, (regvalue &= 0x37)); + + /* Never interrupts */ + gl518_write_value(client, GL518_REG_MASK, 0x00); + + /* Clear status register (D5=1), start (D6=1) */ + gl518_write_value(client, GL518_REG_CONF, 0x20 | regvalue); + gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); +} + +static int gl518_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL518 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int gl518_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return swab16(i2c_smbus_read_word_data(client, reg)); + else + return i2c_smbus_read_byte_data(client, reg); +} + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL518 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_data(client, reg, swab16(value)); + else + return i2c_smbus_write_byte_data(client, reg, value); +} + +static struct gl518_data *gl518_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int val; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting gl518 update\n"); + + data->alarms = gl518_read_value(client, GL518_REG_INT); + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + + val = gl518_read_value(client, GL518_REG_VDD_LIMIT); + data->voltage_min[0] = val & 0xff; + data->voltage_max[0] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); + data->voltage_min[1] = val & 0xff; + data->voltage_max[1] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); + data->voltage_min[2] = val & 0xff; + data->voltage_max[2] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); + data->voltage_min[3] = val & 0xff; + data->voltage_max[3] = (val >> 8) & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_COUNT); + data->fan_in[0] = (val >> 8) & 0xff; + data->fan_in[1] = val & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); + data->temp_max = + gl518_read_value(client, GL518_REG_TEMP_MAX); + data->temp_hyst = + gl518_read_value(client, GL518_REG_TEMP_HYST); + + val = gl518_read_value(client, GL518_REG_MISC); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_auto1 = (val >> 3) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl518_read_value(client, GL518_REG_CONF); + data->beep_enable = (val >> 2) & 1; + + if (data->type != gl518sm_r00) { + data->voltage_in[0] = + gl518_read_value(client, GL518_REG_VDD); + data->voltage_in[1] = + gl518_read_value(client, GL518_REG_VIN1); + data->voltage_in[2] = + gl518_read_value(client, GL518_REG_VIN2); + } + data->voltage_in[3] = + gl518_read_value(client, GL518_REG_VIN3); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_gl518sm_init(void) +{ + return i2c_add_driver(&gl518_driver); +} + +static void __exit sensors_gl518sm_exit(void) +{ + i2c_del_driver(&gl518_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Kyosti Malkki and " + "Hong-Gunn Chew "); +MODULE_DESCRIPTION("GL518SM driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_gl518sm_init); +module_exit(sensors_gl518sm_exit); diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c new file mode 100644 index 00000000000..a13a504f5bf --- /dev/null +++ b/drivers/hwmon/gl520sm.c @@ -0,0 +1,769 @@ +/* + gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard , + Kyösti Mälkki + Copyright (c) 2005 Maarten Deprez + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +/* Type of the extra sensor */ +static unsigned short extra_sensor_type; +module_param(extra_sensor_type, ushort, 0); +MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(gl520sm); + +/* Many GL520 constants specified below +One of the inputs can be configured as either temp or voltage. +That's why _TEMP2 and _IN4 access the same register +*/ + +/* The GL520 registers */ +#define GL520_REG_CHIP_ID 0x00 +#define GL520_REG_REVISION 0x01 +#define GL520_REG_CONF 0x03 +#define GL520_REG_MASK 0x11 + +#define GL520_REG_VID_INPUT 0x02 + +#define GL520_REG_IN0_INPUT 0x15 +#define GL520_REG_IN0_LIMIT 0x0c +#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT +#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT + +#define GL520_REG_IN1_INPUT 0x14 +#define GL520_REG_IN1_LIMIT 0x09 +#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT +#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT + +#define GL520_REG_IN2_INPUT 0x13 +#define GL520_REG_IN2_LIMIT 0x0a +#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT +#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT + +#define GL520_REG_IN3_INPUT 0x0d +#define GL520_REG_IN3_LIMIT 0x0b +#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT +#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT + +#define GL520_REG_IN4_INPUT 0x0e +#define GL520_REG_IN4_MAX 0x17 +#define GL520_REG_IN4_MIN 0x18 + +#define GL520_REG_TEMP1_INPUT 0x04 +#define GL520_REG_TEMP1_MAX 0x05 +#define GL520_REG_TEMP1_MAX_HYST 0x06 + +#define GL520_REG_TEMP2_INPUT 0x0e +#define GL520_REG_TEMP2_MAX 0x17 +#define GL520_REG_TEMP2_MAX_HYST 0x18 + +#define GL520_REG_FAN_INPUT 0x07 +#define GL520_REG_FAN_MIN 0x08 +#define GL520_REG_FAN_DIV 0x0f +#define GL520_REG_FAN_OFF GL520_REG_FAN_DIV + +#define GL520_REG_ALARMS 0x12 +#define GL520_REG_BEEP_MASK 0x10 +#define GL520_REG_BEEP_ENABLE GL520_REG_CONF + +/* + * Function declarations + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter); +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind); +static void gl520_init_client(struct i2c_client *client); +static int gl520_detach_client(struct i2c_client *client); +static int gl520_read_value(struct i2c_client *client, u8 reg); +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct gl520_data *gl520_update_device(struct device *dev); + +/* Driver data */ +static struct i2c_driver gl520_driver = { + .owner = THIS_MODULE, + .name = "gl520sm", + .id = I2C_DRIVERID_GL520, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl520_attach_adapter, + .detach_client = gl520_detach_client, +}; + +/* Client data */ +struct gl520_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until the following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + u8 vid; + u8 vrm; + u8 in_input[5]; /* [0] = VVD */ + u8 in_min[5]; /* [0] = VDD */ + u8 in_max[5]; /* [0] = VDD */ + u8 fan_input[2]; + u8 fan_min[2]; + u8 fan_div[2]; + u8 fan_off; + u8 temp_input[2]; + u8 temp_max[2]; + u8 temp_max_hyst[2]; + u8 alarms; + u8 beep_enable; + u8 beep_mask; + u8 alarm_mask; + u8 two_temps; +}; + +/* + * Sysfs stuff + */ + +#define sysfs_r(type, n, item, reg) \ +static ssize_t get_##type##item (struct gl520_data *, char *, int); \ +static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ +static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl520_data *data = gl520_update_device(dev); \ + return get_##type##item(data, buf, (n)); \ +} + +#define sysfs_w(type, n, item, reg) \ +static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ +static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl520_data *data = i2c_get_clientdata(client); \ + return set_##type##item(client, data, buf, count, (n), reg); \ +} + +#define sysfs_rw_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +sysfs_w(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); + +#define sysfs_ro_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); + +#define sysfs_rw(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +sysfs_w(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); + +#define sysfs_ro(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); + + +#define sysfs_vid(n) \ +sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) + +#define device_create_file_vid(client, n) \ +device_create_file(&client->dev, &dev_attr_cpu##n##_vid) + +#define sysfs_in(n) \ +sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ +sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ +sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ + +#define device_create_file_in(client, n) \ +({device_create_file(&client->dev, &dev_attr_in##n##_input); \ +device_create_file(&client->dev, &dev_attr_in##n##_min); \ +device_create_file(&client->dev, &dev_attr_in##n##_max);}) + +#define sysfs_fan(n) \ +sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ +sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ +sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) + +#define device_create_file_fan(client, n) \ +({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ +device_create_file(&client->dev, &dev_attr_fan##n##_min); \ +device_create_file(&client->dev, &dev_attr_fan##n##_div);}) + +#define sysfs_fan_off(n) \ +sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ + +#define device_create_file_fan_off(client, n) \ +device_create_file(&client->dev, &dev_attr_fan##n##_off) + +#define sysfs_temp(n) \ +sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ +sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ +sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) + +#define device_create_file_temp(client, n) \ +({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) + +#define sysfs_alarms() \ +sysfs_ro(alarms, , GL520_REG_ALARMS) \ +sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ +sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) + +#define device_create_file_alarms(client) \ +({device_create_file(&client->dev, &dev_attr_alarms); \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask);}) + + +sysfs_vid(0) + +sysfs_in(0) +sysfs_in(1) +sysfs_in(2) +sysfs_in(3) +sysfs_in(4) + +sysfs_fan(1) +sysfs_fan(2) +sysfs_fan_off(1) + +sysfs_temp(1) +sysfs_temp(2) + +sysfs_alarms() + + +static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} + +#define VDD_FROM_REG(val) (((val)*95+2)/4) +#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) + +#define IN_FROM_REG(val) ((val)*19) +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) + +static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_input[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_min[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_max[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + down(&data->update_lock); + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + data->in_min[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + else + gl520_write_value(client, reg, r); + + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + down(&data->update_lock); + + data->in_max[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, r); + + up(&data->update_lock); + return count; +} + +#define DIV_FROM_REG(val) (1 << (val)) +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) +#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); + +static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); +} + +static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->fan_off); +} + +static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + + down(&data->update_lock); + r = FAN_TO_REG(v, data->fan_div[n - 1]); + data->fan_min[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + if (data->fan_min[n - 1] == 0) + data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; + else + data->alarm_mask |= (n == 1) ? 0x20 : 0x40; + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + + switch (v) { + case 1: r = 0; break; + case 2: r = 1; break; + case 4: r = 2; break; + case 8: r = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + data->fan_div[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?1:0; + + down(&data->update_lock); + data->fan_off = r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); + up(&data->update_lock); + return count; +} + +#define TEMP_FROM_REG(val) (((val) - 130) * 1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) + +static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); +} + +static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); +} + +static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); +} + +static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[n - 1] = TEMP_TO_REG(v);; + gl520_write_value(client, reg, data->temp_max[n - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); + gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_enable); +} + +static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_mask); +} + +static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?0:1; + + down(&data->update_lock); + data->beep_enable = !r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); + up(&data->update_lock); + return count; +} + +static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + r &= data->alarm_mask; + data->beep_mask = r; + gl520_write_value(client, reg, r); + up(&data->update_lock); + return count; +} + + +/* + * Real code + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, gl520_detect); +} + +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct gl520_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access gl520_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct gl520_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &gl520_driver; + new_client->flags = 0; + + /* Determine the chip type. */ + if (kind < 0) { + if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || + ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || + ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { + dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); + goto exit_free; + } + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the GL520SM chip */ + gl520_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file_vid(new_client, 0); + + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + if (!data->two_temps) + device_create_file_in(new_client, 4); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan_off(new_client, 1); + + device_create_file_temp(new_client, 1); + if (data->two_temps) + device_create_file_temp(new_client, 2); + + device_create_file_alarms(new_client); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + + +/* Called when we have found a new GL520SM. */ +static void gl520_init_client(struct i2c_client *client) +{ + struct gl520_data *data = i2c_get_clientdata(client); + u8 oldconf, conf; + + conf = oldconf = gl520_read_value(client, GL520_REG_CONF); + + data->alarm_mask = 0xff; + data->vrm = i2c_which_vrm(); + + if (extra_sensor_type == 1) + conf &= ~0x10; + else if (extra_sensor_type == 2) + conf |= 0x10; + data->two_temps = !(conf & 0x10); + + /* If IRQ# is disabled, we can safely force comparator mode */ + if (!(conf & 0x20)) + conf &= 0xf7; + + /* Enable monitoring if needed */ + conf |= 0x40; + + if (conf != oldconf) + gl520_write_value(client, GL520_REG_CONF, conf); + + gl520_update_device(&(client->dev)); + + if (data->fan_min[0] == 0) + data->alarm_mask &= ~0x20; + if (data->fan_min[1] == 0) + data->alarm_mask &= ~0x40; + + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); +} + +static int gl520_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL520 uses a high-byte first convention */ +static int gl520_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return swab16(i2c_smbus_read_word_data(client, reg)); + else + return i2c_smbus_read_byte_data(client, reg); +} + +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_data(client, reg, swab16(value)); + else + return i2c_smbus_write_byte_data(client, reg, value); +} + + +static struct gl520_data *gl520_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int val; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + + dev_dbg(&client->dev, "Starting gl520sm update\n"); + + data->alarms = gl520_read_value(client, GL520_REG_ALARMS); + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; + + val = gl520_read_value(client, GL520_REG_IN0_LIMIT); + data->in_min[0] = val & 0xff; + data->in_max[0] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN1_LIMIT); + data->in_min[1] = val & 0xff; + data->in_max[1] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN2_LIMIT); + data->in_min[2] = val & 0xff; + data->in_max[2] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN3_LIMIT); + data->in_min[3] = val & 0xff; + data->in_max[3] = (val >> 8) & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_INPUT); + data->fan_input[0] = (val >> 8) & 0xff; + data->fan_input[1] = val & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_MIN); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); + data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); + data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); + + val = gl520_read_value(client, GL520_REG_FAN_DIV); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_off = (val >> 2) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl520_read_value(client, GL520_REG_CONF); + data->beep_enable = !((val >> 2) & 1); + + data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); + data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); + data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); + data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); + + /* Temp1 and Vin4 are the same input */ + if (data->two_temps) { + data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); + data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); + data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); + } else { + data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); + data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); + data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + + +static int __init sensors_gl520sm_init(void) +{ + return i2c_add_driver(&gl520_driver); +} + +static void __exit sensors_gl520sm_exit(void) +{ + i2c_del_driver(&gl520_driver); +} + + +MODULE_AUTHOR("Frodo Looijaard , " + "Kyösti Mälkki , " + "Maarten Deprez "); +MODULE_DESCRIPTION("GL520SM driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_gl520sm_init); +module_exit(sensors_gl520sm_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c new file mode 100644 index 00000000000..db20c9e4739 --- /dev/null +++ b/drivers/hwmon/it87.c @@ -0,0 +1,1184 @@ +/* + it87.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring. + + 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 + Largely inspired by lm78.c of the same package + + 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. +*/ + +/* + djg@pdp8.net David Gesswein 7/18/01 + Modified to fix bug with not all alarms enabled. + Added ability to read battery voltage and select temperature sensor + type at module load time. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +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 */ +SENSORS_INSMOD_2(it87, it8712); + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ +#define PME 0x04 /* The device with the fan registers in it */ +#define DEVID 0x20 /* Register: Device ID */ +#define DEVREV 0x22 /* Register: Device Revision */ + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static int superio_inw(int reg) +{ + int val; + outb(reg++, REG); + val = inb(VAL) << 8; + outb(reg, REG); + val |= inb(VAL); + return val; +} + +static inline void +superio_select(void) +{ + outb(DEV, REG); + outb(PME, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x01, REG); + outb(0x55, REG); + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +#define IT8712F_DEVID 0x8712 +#define IT8705F_DEVID 0x8705 +#define IT87_ACT_REG 0x30 +#define IT87_BASE_REG 0x60 + +/* 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; + +/* Many IT87 constants specified below */ + +/* Length of ISA address segment */ +#define IT87_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define IT87_ADDR_REG_OFFSET 5 +#define IT87_DATA_REG_OFFSET 6 + +/*----- The IT87 registers -----*/ + +#define IT87_REG_CONFIG 0x00 + +#define IT87_REG_ALARM1 0x01 +#define IT87_REG_ALARM2 0x02 +#define IT87_REG_ALARM3 0x03 + +#define IT87_REG_VID 0x0a +#define IT87_REG_FAN_DIV 0x0b + +/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ + +#define IT87_REG_FAN(nr) (0x0d + (nr)) +#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) +#define IT87_REG_FAN_MAIN_CTRL 0x13 +#define IT87_REG_FAN_CTL 0x14 +#define IT87_REG_PWM(nr) (0x15 + (nr)) + +#define IT87_REG_VIN(nr) (0x20 + (nr)) +#define IT87_REG_TEMP(nr) (0x29 + (nr)) + +#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) +#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) +#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) +#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) + +#define IT87_REG_I2C_ADDR 0x48 + +#define IT87_REG_VIN_ENABLE 0x50 +#define IT87_REG_TEMP_ENABLE 0x51 + +#define IT87_REG_CHIPID 0x58 + +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, + 254); +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ + ((val)+500)/1000),-128,127)) +#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) + +#define PWM_TO_REG(val) ((val) >> 1) +#define PWM_FROM_REG(val) (((val)&0x7f) << 1) + +static int DIV_TO_REG(int val) +{ + int answer = 0; + while ((val >>= 1) != 0) + answer++; + return answer; +} +#define DIV_FROM_REG(val) (1 << (val)) + + +/* For each registered IT87, we need to keep some data in memory. That + data is pointed to by it87_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new it87 client is + allocated. */ +struct it87_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[9]; /* Register value */ + u8 in_max[9]; /* Register value */ + u8 in_min[9]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp[3]; /* Register value */ + u8 temp_high[3]; /* Register value */ + u8 temp_low[3]; /* Register value */ + u8 sensor; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + int vrm; + u32 alarms; /* Register encoding, combined */ + u8 fan_main_ctrl; /* Register value */ + u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ +}; + + +static int it87_attach_adapter(struct i2c_adapter *adapter); +static int it87_find(int *address); +static int it87_detect(struct i2c_adapter *adapter, int address, int kind); +static int it87_detach_client(struct i2c_client *client); + +static int it87_read_value(struct i2c_client *client, u8 register); +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); + + +static struct i2c_driver it87_driver = { + .owner = THIS_MODULE, + .name = "it87", + .id = I2C_DRIVERID_IT87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = it87_attach_adapter, + .detach_client = it87_detach_client, +}; + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + it87_write_value(client, IT87_REG_VIN_MIN(nr), + data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + it87_write_value(client, IT87_REG_VIN_MAX(nr), + data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); + +#define limit_in_offset(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); + +show_in_offset(0); +limit_in_offset(0); +show_in_offset(1); +limit_in_offset(1); +show_in_offset(2); +limit_in_offset(2); +show_in_offset(3); +limit_in_offset(3); +show_in_offset(4); +limit_in_offset(4); +show_in_offset(5); +limit_in_offset(5); +show_in_offset(6); +limit_in_offset(6); +show_in_offset(7); +limit_in_offset(7); +show_in_offset(8); + +/* 3 temperatures */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); +} +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); +} +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); +} +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_high[nr] = TEMP_TO_REG(val); + it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_low[nr] = TEMP_TO_REG(val); + it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_offset(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); + +show_temp_offset(1); +show_temp_offset(2); +show_temp_offset(3); + +static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + u8 reg = data->sensor; /* In case the value is updated while we use it */ + + if (reg & (1 << nr)) + return sprintf(buf, "3\n"); /* thermal diode */ + if (reg & (8 << nr)) + return sprintf(buf, "2\n"); /* thermistor */ + return sprintf(buf, "0\n"); /* disabled */ +} +static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + + data->sensor &= ~(1 << nr); + data->sensor &= ~(8 << nr); + /* 3 = thermal diode; 2 = thermistor; 0 = disabled */ + if (val == 3) + data->sensor |= 1 << nr; + else if (val == 2) + data->sensor |= 8 << nr; + else if (val != 0) { + up(&data->update_lock); + return -EINVAL; + } + it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); + up(&data->update_lock); + return count; +} +#define show_sensor_offset(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_sensor, set_sensor, offset - 1); + +show_sensor_offset(1); +show_sensor_offset(2); +show_sensor_offset(3); + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", + FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); +} +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); +} +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int i, min[3]; + u8 old; + + down(&data->update_lock); + old = it87_read_value(client, IT87_REG_FAN_DIV); + + for (i = 0; i < 3; i++) + min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); + + switch (nr) { + case 0: + case 1: + data->fan_div[nr] = DIV_TO_REG(val); + break; + case 2: + if (val < 8) + data->fan_div[nr] = 1; + else + data->fan_div[nr] = 3; + } + val = old & 0x80; + val |= (data->fan_div[0] & 0x07); + val |= (data->fan_div[1] & 0x07) << 3; + if (data->fan_div[2] == 3) + val |= 0x1 << 6; + it87_write_value(client, IT87_REG_FAN_DIV, val); + + for (i = 0; i < 3; i++) { + data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); + it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); + } + up(&data->update_lock); + return count; +} +static ssize_t set_pwm_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + + if (val == 0) { + int tmp; + /* make sure the fan is on when in on/off mode */ + tmp = it87_read_value(client, IT87_REG_FAN_CTL); + it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr)); + /* set on/off mode */ + data->fan_main_ctrl &= ~(1 << nr); + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + } else if (val == 1) { + /* set SmartGuardian mode */ + data->fan_main_ctrl |= (1 << nr); + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + /* set saved pwm value, clear FAN_CTLX PWM mode bit */ + it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); + } else { + up(&data->update_lock); + return -EINVAL; + } + + up(&data->update_lock); + return count; +} +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + down(&data->update_lock); + data->manual_pwm_ctl[nr] = val; + if (data->fan_main_ctrl & (1 << nr)) + it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +#define show_pwm_offset(offset) \ +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_pwm_enable, set_pwm_enable, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); + +show_pwm_offset(1); +show_pwm_offset(2); +show_pwm_offset(3); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +/* This function is called when: + * it87_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and it87_driver is still present) */ +static int it87_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, it87_detect); +} + +/* SuperIO detection - will change normal_isa[0] if a chip is found */ +static int it87_find(int *address) +{ + int err = -ENODEV; + + superio_enter(); + chip_type = superio_inw(DEVID); + if (chip_type != IT8712F_DEVID + && chip_type != IT8705F_DEVID) + goto exit; + + superio_select(); + if (!(superio_inb(IT87_ACT_REG) & 0x01)) { + pr_info("it87: Device not activated, skipping\n"); + goto exit; + } + + *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); + if (*address == 0) { + pr_info("it87: Base address not set, skipping\n"); + goto exit; + } + + err = 0; + pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", + chip_type, *address, superio_inb(DEVREV) & 0x0f); + +exit: + superio_exit(); + return err; +} + +/* This function is called by i2c_detect */ +int it87_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct it87_data *data; + int err = 0; + const char *name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + int enable_pwm_interface; + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto ERROR0; + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, IT87_EXTENT, it87_driver.name)) + goto ERROR0; + + /* Probe whether there is anything available on this address. Already + done for SMBus and Super-I/O clients */ + if (kind < 0) { + if (is_isa && !chip_type) { +#define REALLY_SLOW_IO + /* We need the timeouts for at least some IT87-like chips. But only + if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i + || inb_p(address + 3) != i + || inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* 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 it87_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct it87_data)); + + new_client = &data->client; + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &it87_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) + || (!is_isa + && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = it87_read_value(new_client, IT87_REG_CHIPID); + if (i == 0x90) { + kind = it87; + if ((is_isa) && (chip_type == IT8712F_DEVID)) + kind = it8712; + } + else { + if (kind == 0) + dev_info(&adapter->dev, + "Ignoring 'force' parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == it87) { + name = "it87"; + } else if (kind == it8712) { + name = "it8712"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + 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 ERROR2; + + /* Check PWM configuration */ + enable_pwm_interface = it87_check_pwm(new_client); + + /* Initialize the IT87 chip */ + it87_init_client(new_client, data); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (enable_pwm_interface) { + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); + } + + if (data->type == it8712) { + data->vrm = i2c_which_vrm(); + device_create_file_vrm(new_client); + device_create_file_vid(new_client); + } + + return 0; + +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, IT87_EXTENT); +ERROR0: + return err; +} + +static int it87_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if(i2c_is_isa_client(client)) + release_region(client->addr, IT87_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + would slow down the IT87 access and should not be necessary. */ +static int it87_read_value(struct i2c_client *client, u8 reg) +{ + struct it87_data *data = i2c_get_clientdata(client); + + int res; + if (i2c_is_isa_client(client)) { + down(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + res = inb_p(client->addr + IT87_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + would slow down the IT87 access and should not be necessary. */ +static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + struct it87_data *data = i2c_get_clientdata(client); + + if (i2c_is_isa_client(client)) { + down(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + outb_p(value, client->addr + IT87_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + 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) +{ + int tmp, i; + + /* initialize to sane defaults: + * - if the chip is in manual pwm mode, this will be overwritten with + * the actual settings on the chip (so in this case, initialization + * is not needed) + * - if in automatic or on/off mode, we could switch to manual mode, + * read the registers and set manual_pwm_ctl accordingly, but currently + * this is not implemented, so we initialize to something sane */ + for (i = 0; i < 3; i++) { + data->manual_pwm_ctl[i] = 0xff; + } + + /* Check if temperature channnels are reset manually or by some reason */ + tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); + if ((tmp & 0x3f) == 0) { + /* Temp1,Temp3=thermistor; Temp2=thermal diode */ + tmp = (tmp & 0xc0) | 0x2a; + it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); + } + data->sensor = tmp; + + /* Check if voltage monitors are reset manually or by some reason */ + tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); + if ((tmp & 0xff) == 0) { + /* Enable all voltage monitors */ + it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); + } + + /* Check if tachometers are reset manually or by some reason */ + data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); + if ((data->fan_main_ctrl & 0x70) == 0) { + /* Enable all fan tachometers */ + data->fan_main_ctrl |= 0x70; + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + } + + /* Set current fan mode registers and the default settings for the + * other mode registers */ + for (i = 0; i < 3; i++) { + if (data->fan_main_ctrl & (1 << i)) { + /* pwm mode */ + tmp = it87_read_value(client, IT87_REG_PWM(i)); + if (tmp & 0x80) { + /* automatic pwm - not yet implemented, but + * leave the settings made by the BIOS alone + * until a change is requested via the sysfs + * interface */ + } else { + /* manual pwm */ + data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp); + } + } + } + + /* Start monitoring */ + it87_write_value(client, IT87_REG_CONFIG, + (it87_read_value(client, IT87_REG_CONFIG) & 0x36) + | (update_vbat ? 0x41 : 0x01)); +} + +static struct it87_data *it87_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + if (update_vbat) { + /* Cleared after each update, so reenable. Value + returned by this read will be previous value */ + it87_write_value(client, IT87_REG_CONFIG, + it87_read_value(client, IT87_REG_CONFIG) | 0x40); + } + for (i = 0; i <= 7; i++) { + data->in[i] = + it87_read_value(client, IT87_REG_VIN(i)); + data->in_min[i] = + it87_read_value(client, IT87_REG_VIN_MIN(i)); + data->in_max[i] = + it87_read_value(client, IT87_REG_VIN_MAX(i)); + } + data->in[8] = + it87_read_value(client, IT87_REG_VIN(8)); + /* Temperature sensor doesn't have limit registers, set + to min and max value */ + data->in_min[8] = 0; + data->in_max[8] = 255; + + for (i = 0; i < 3; i++) { + data->fan[i] = + it87_read_value(client, IT87_REG_FAN(i)); + data->fan_min[i] = + it87_read_value(client, IT87_REG_FAN_MIN(i)); + } + for (i = 0; i < 3; i++) { + data->temp[i] = + it87_read_value(client, IT87_REG_TEMP(i)); + data->temp_high[i] = + it87_read_value(client, IT87_REG_TEMP_HIGH(i)); + data->temp_low[i] = + it87_read_value(client, IT87_REG_TEMP_LOW(i)); + } + + i = it87_read_value(client, IT87_REG_FAN_DIV); + data->fan_div[0] = i & 0x07; + data->fan_div[1] = (i >> 3) & 0x07; + data->fan_div[2] = (i & 0x40) ? 3 : 1; + + data->alarms = + it87_read_value(client, IT87_REG_ALARM1) | + (it87_read_value(client, IT87_REG_ALARM2) << 8) | + (it87_read_value(client, IT87_REG_ALARM3) << 16); + data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); + + data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); + /* The 8705 does not have VID capability */ + if (data->type == it8712) { + data->vid = it87_read_value(client, IT87_REG_VID); + data->vid &= 0x1f; + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sm_it87_init(void) +{ + int addr; + + if (!it87_find(&addr)) { + normal_isa[0] = addr; + } + return i2c_add_driver(&it87_driver); +} + +static void __exit sm_it87_exit(void) +{ + i2c_del_driver(&it87_driver); +} + + +MODULE_AUTHOR("Chris Gauthron "); +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); +module_exit(sm_it87_exit); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c new file mode 100644 index 00000000000..7c6f9ea5a25 --- /dev/null +++ b/drivers/hwmon/lm63.c @@ -0,0 +1,597 @@ +/* + * lm63.c - driver for the National Semiconductor LM63 temperature sensor + * with integrated fan control + * Copyright (C) 2004-2005 Jean Delvare + * Based on the lm90 driver. + * + * The LM63 is a sensor chip made by National Semiconductor. It measures + * two temperatures (its own and one external one) and the speed of one + * fan, those speed it can additionally control. Complete datasheet can be + * obtained from National's website at: + * http://www.national.com/pf/LM/LM63.html + * + * The LM63 is basically an LM86 with fan speed monitoring and control + * capabilities added. It misses some of the LM86 features though: + * - No low limit for local temperature. + * - No critical limit for local temperature. + * - Critical limit for remote temperature can be changed only once. We + * will consider that the critical limit is read-only. + * + * The datasheet isn't very clear about what the tachometer reading is. + * I had a explanation from National Semiconductor though. The two lower + * bits of the read value have to be masked out. The value is still 16 bit + * in width. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is fully defined internally and cannot be changed. + */ + +static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm63); + +/* + * The LM63 registers + */ + +#define LM63_REG_CONFIG1 0x03 +#define LM63_REG_CONFIG2 0xBF +#define LM63_REG_CONFIG_FAN 0x4A + +#define LM63_REG_TACH_COUNT_MSB 0x47 +#define LM63_REG_TACH_COUNT_LSB 0x46 +#define LM63_REG_TACH_LIMIT_MSB 0x49 +#define LM63_REG_TACH_LIMIT_LSB 0x48 + +#define LM63_REG_PWM_VALUE 0x4C +#define LM63_REG_PWM_FREQ 0x4D + +#define LM63_REG_LOCAL_TEMP 0x00 +#define LM63_REG_LOCAL_HIGH 0x05 + +#define LM63_REG_REMOTE_TEMP_MSB 0x01 +#define LM63_REG_REMOTE_TEMP_LSB 0x10 +#define LM63_REG_REMOTE_OFFSET_MSB 0x11 +#define LM63_REG_REMOTE_OFFSET_LSB 0x12 +#define LM63_REG_REMOTE_HIGH_MSB 0x07 +#define LM63_REG_REMOTE_HIGH_LSB 0x13 +#define LM63_REG_REMOTE_LOW_MSB 0x08 +#define LM63_REG_REMOTE_LOW_LSB 0x14 +#define LM63_REG_REMOTE_TCRIT 0x19 +#define LM63_REG_REMOTE_TCRIT_HYST 0x21 + +#define LM63_REG_ALERT_STATUS 0x02 +#define LM63_REG_ALERT_MASK 0x16 + +#define LM63_REG_MAN_ID 0xFE +#define LM63_REG_CHIP_ID 0xFF + +/* + * Conversions and various macros + * For tachometer counts, the LM63 uses 16-bit values. + * For local temperature and high limit, remote critical limit and hysteresis + * value, it uses signed 8-bit values with LSB = 1 degree Celsius. + * For remote temperature, low and high limits, it uses signed 11-bit values + * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + */ + +#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ + 5400000 / (reg)) +#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \ + (5400000 / (val)) & 0xFFFC) +#define TEMP8_FROM_REG(reg) ((reg) * 1000) +#define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) +#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) +#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ + (val) >= 127875 ? 0x7FE0 : \ + (val) < 0 ? ((val) - 62) / 125 * 32 : \ + ((val) + 62) / 125 * 32) +#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 127000 ? 127 : \ + ((val) + 500) / 1000) + +/* + * Functions declaration + */ + +static int lm63_attach_adapter(struct i2c_adapter *adapter); +static int lm63_detach_client(struct i2c_client *client); + +static struct lm63_data *lm63_update_device(struct device *dev); + +static int lm63_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm63_init_client(struct i2c_client *client); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm63_driver = { + .owner = THIS_MODULE, + .name = "lm63", + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm63_attach_adapter, + .detach_client = lm63_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm63_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 config, config_fan; + u16 fan[2]; /* 0: input + 1: low limit */ + u8 pwm1_freq; + u8 pwm1_value; + s8 temp8[3]; /* 0: local input + 1: local high limit + 2: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ + u8 temp2_crit_hyst; + u8 alarms; +}; + +/* + * Sysfs callback functions and files + */ + +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan[1] = FAN_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, + data->fan[1] & 0xFF); + i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, + data->fan[1] >> 8); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? + 255 : (data->pwm1_value * 255 + data->pwm1_freq) / + (2 * data->pwm1_freq)); +} + +static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (!(data->config_fan & 0x20)) /* register is read-only */ + return -EPERM; + + val = simple_strtoul(buf, NULL, 10); + down(&data->update_lock); + data->pwm1_value = val <= 0 ? 0 : + val >= 255 ? 2 * data->pwm1_freq : + (val * data->pwm1_freq * 2 + 127) / 255; + i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); +} + +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp8[1] = TEMP8_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); +} + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM63_REG_REMOTE_LOW_MSB, + LM63_REG_REMOTE_LOW_LSB, + LM63_REG_REMOTE_HIGH_MSB, + LM63_REG_REMOTE_HIGH_LSB, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp11[nr] = TEMP11_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; +} + +/* Hysteresis register holds a relative value, while we want to present + an absolute to user-space */ +static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) + - TEMP8_FROM_REG(data->temp2_crit_hyst)); +} + +/* And now the other way around, user-space provides an absolute + hysteresis value and we have to store a relative one */ +static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + long hyst; + + down(&data->update_lock); + hyst = TEMP8_FROM_REG(data->temp8[2]) - val; + i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, + HYST_TO_REG(hyst)); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, + set_fan, 1); + +static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); +static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); + +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); +static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, + set_temp2_crit_hyst); + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm63_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm63_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm63_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm63_data)); + + /* The common I2C client data is placed right before the + LM63-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm63_driver; + new_client->flags = 0; + + /* Default to an LM63 if forced */ + if (kind == 0) + kind = lm63; + + if (kind < 0) { /* must identify */ + u8 man_id, chip_id, reg_config1, reg_config2; + u8 reg_alert_status, reg_alert_mask; + + man_id = i2c_smbus_read_byte_data(new_client, + LM63_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM63_REG_CHIP_ID); + reg_config1 = i2c_smbus_read_byte_data(new_client, + LM63_REG_CONFIG1); + reg_config2 = i2c_smbus_read_byte_data(new_client, + LM63_REG_CONFIG2); + reg_alert_status = i2c_smbus_read_byte_data(new_client, + LM63_REG_ALERT_STATUS); + reg_alert_mask = i2c_smbus_read_byte_data(new_client, + LM63_REG_ALERT_MASK); + + if (man_id == 0x01 /* National Semiconductor */ + && chip_id == 0x41 /* LM63 */ + && (reg_config1 & 0x18) == 0x00 + && (reg_config2 & 0xF8) == 0x00 + && (reg_alert_status & 0x20) == 0x00 + && (reg_alert_mask & 0xA4) == 0xA4) { + kind = lm63; + } else { /* failed */ + dev_dbg(&adapter->dev, "Unsupported chip " + "(man_id=0x%02X, chip_id=0x%02X).\n", + man_id, chip_id); + goto exit_free; + } + } + + strlcpy(new_client->name, "lm63", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM63 chip */ + lm63_init_client(new_client); + + /* Register sysfs hooks */ + if (data->config & 0x04) { /* tachometer enabled */ + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + } + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +/* Idealy we shouldn't have to initialize anything, since the BIOS + should have taken care of everything */ +static void lm63_init_client(struct i2c_client *client) +{ + struct lm63_data *data = i2c_get_clientdata(client); + + data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); + data->config_fan = i2c_smbus_read_byte_data(client, + LM63_REG_CONFIG_FAN); + + /* Start converting if needed */ + if (data->config & 0x40) { /* standby */ + dev_dbg(&client->dev, "Switching to operational mode"); + data->config &= 0xA7; + i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, + data->config); + } + + /* We may need pwm1_freq before ever updating the client data */ + data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); + if (data->pwm1_freq == 0) + data->pwm1_freq = 1; + + /* Show some debug info about the LM63 configuration */ + dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", + (data->config & 0x04) ? "tachometer input" : + "alert output"); + dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", + (data->config_fan & 0x08) ? "1.4" : "360", + ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); + dev_dbg(&client->dev, "PWM output active %s, %s mode\n", + (data->config_fan & 0x10) ? "low" : "high", + (data->config_fan & 0x20) ? "manual" : "auto"); +} + +static int lm63_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 struct lm63_data *lm63_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + if (data->config & 0x04) { /* tachometer enabled */ + /* order matters for fan1_input */ + data->fan[0] = i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_LSB) & 0xFC; + data->fan[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_MSB) << 8; + data->fan[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_LSB) & 0xFC) + | (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_MSB) << 8); + } + + data->pwm1_freq = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_FREQ); + if (data->pwm1_freq == 0) + data->pwm1_freq = 1; + data->pwm1_value = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_VALUE); + + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_HIGH); + + /* order matters for temp2_input */ + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_MSB) << 8; + data->temp11[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_LSB); + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_LOW_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_LOW_LSB); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT); + data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT_HYST); + + data->alarms = i2c_smbus_read_byte_data(client, + LM63_REG_ALERT_STATUS) & 0x7F; + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm63_init(void) +{ + return i2c_add_driver(&lm63_driver); +} + +static void __exit sensors_lm63_exit(void) +{ + i2c_del_driver(&lm63_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM63 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm63_init); +module_exit(sensors_lm63_exit); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c new file mode 100644 index 00000000000..5be164ed278 --- /dev/null +++ b/drivers/hwmon/lm75.c @@ -0,0 +1,296 @@ +/* + lm75.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm75); + +/* Many LM75 constants specified below */ + +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_TEMP_HYST 0x02 +#define LM75_REG_TEMP_OS 0x03 + +/* Each client has this additional data */ +struct lm75_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 temp_input; /* Register values */ + u16 temp_max; + u16 temp_hyst; +}; + +static int lm75_attach_adapter(struct i2c_adapter *adapter); +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm75_init_client(struct i2c_client *client); +static int lm75_detach_client(struct i2c_client *client); +static int lm75_read_value(struct i2c_client *client, u8 reg); +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct lm75_data *lm75_update_device(struct device *dev); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm75_driver = { + .owner = THIS_MODULE, + .name = "lm75", + .id = I2C_DRIVERID_LM75, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm75_attach_adapter, + .detach_client = lm75_detach_client, +}; + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm75_data *data = lm75_update_device(dev); \ + return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm75_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = LM75_TEMP_TO_REG(temp); \ + lm75_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set(temp_max, LM75_REG_TEMP_OS); +set(temp_hyst, LM75_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); + +static int lm75_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm75_detect); +} + +/* This function is called by i2c_detect */ +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct lm75_data *data; + int err = 0; + const char *name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + dev_dbg(&adapter->dev, + "lm75_detect called for an ISA bus adapter?!?\n"); + goto exit; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm75_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm75_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm75_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. There is no identification- + dedicated register so we have to rely on several tricks: + unused bits, registers cycling over 8-address boundaries, + addresses 0x04-0x07 returning the last read value. + The cycling+unused addresses combination is not tested, + since it would significantly slow the detection down and would + hardly add any value. */ + if (kind < 0) { + int cur, conf, hyst, os; + + /* Unused addresses */ + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + if (i2c_smbus_read_word_data(new_client, 4) != hyst + || i2c_smbus_read_word_data(new_client, 5) != hyst + || i2c_smbus_read_word_data(new_client, 6) != hyst + || i2c_smbus_read_word_data(new_client, 7) != hyst) + goto exit_free; + os = i2c_smbus_read_word_data(new_client, 3); + if (i2c_smbus_read_word_data(new_client, 4) != os + || i2c_smbus_read_word_data(new_client, 5) != os + || i2c_smbus_read_word_data(new_client, 6) != os + || i2c_smbus_read_word_data(new_client, 7) != os) + goto exit_free; + + /* Unused bits */ + if (conf & 0xe0) + goto exit_free; + + /* Addresses cycling */ + for (i = 8; i < 0xff; i += 8) + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_word_data(new_client, i + 2) != hyst + || i2c_smbus_read_word_data(new_client, i + 3) != os) + goto exit_free; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm75; + + if (kind == lm75) { + name = "lm75"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM75 chip */ + lm75_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm75_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int lm75_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void lm75_init_client(struct i2c_client *client) +{ + /* Initialize the LM75 chip */ + lm75_write_value(client, LM75_REG_CONF, 0); +} + +static struct lm75_data *lm75_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm75 update\n"); + + data->temp_input = lm75_read_value(client, LM75_REG_TEMP); + data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); + data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm75_init(void) +{ + return i2c_add_driver(&lm75_driver); +} + +static void __exit sensors_lm75_exit(void) +{ + i2c_del_driver(&lm75_driver); +} + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM75 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm75_init); +module_exit(sensors_lm75_exit); diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h new file mode 100644 index 00000000000..63e3f2fb4c2 --- /dev/null +++ b/drivers/hwmon/lm75.h @@ -0,0 +1,49 @@ +/* + lm75.h - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 2003 Mark M. Hoffman + + 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. +*/ + +/* + This file contains common code for encoding/decoding LM75 type + temperature readings, which are emulated by many of the chips + we support. As the user is unlikely to load more than one driver + which contains this code, we don't worry about the wasted space. +*/ + +#include + +/* straight from the datasheet */ +#define LM75_TEMP_MIN (-55000) +#define LM75_TEMP_MAX 125000 + +/* TEMP: 0.001C/bit (-55C to +125C) + REG: (0.5C/bit, two's complement) << 7 */ +static inline u16 LM75_TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + ntemp += (ntemp<0 ? -250 : 250); + return (u16)((ntemp / 500) << 7); +} + +static inline int LM75_TEMP_FROM_REG(u16 reg) +{ + /* use integer division instead of equivalent right shift to + guarantee arithmetic shift and preserve the sign */ + return ((s16)reg / 128) * 500; +} + diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c new file mode 100644 index 00000000000..b98f4495299 --- /dev/null +++ b/drivers/hwmon/lm77.c @@ -0,0 +1,420 @@ +/* + lm77.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 2004 Andras BALI + + Heavily based on lm75.c by Frodo Looijaard . The LM77 + is a temperature sensor and thermal window comparator with 0.5 deg + resolution made by National Semiconductor. Complete datasheet can be + obtained at their site: + http://www.national.com/pf/LM/LM77.html + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm77); + +/* The LM77 registers */ +#define LM77_REG_TEMP 0x00 +#define LM77_REG_CONF 0x01 +#define LM77_REG_TEMP_HYST 0x02 +#define LM77_REG_TEMP_CRIT 0x03 +#define LM77_REG_TEMP_MIN 0x04 +#define LM77_REG_TEMP_MAX 0x05 + +/* Each client has this additional data */ +struct lm77_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + int temp_input; /* Temperatures */ + int temp_crit; + int temp_min; + int temp_max; + int temp_hyst; + u8 alarms; +}; + +static int lm77_attach_adapter(struct i2c_adapter *adapter); +static int lm77_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm77_init_client(struct i2c_client *client); +static int lm77_detach_client(struct i2c_client *client); +static u16 lm77_read_value(struct i2c_client *client, u8 reg); +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); + +static struct lm77_data *lm77_update_device(struct device *dev); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm77_driver = { + .owner = THIS_MODULE, + .name = "lm77", + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm77_attach_adapter, + .detach_client = lm77_detach_client, +}; + +/* straight from the datasheet */ +#define LM77_TEMP_MIN (-55000) +#define LM77_TEMP_MAX 125000 + +/* In the temperature registers, the low 3 bits are not part of the + temperature values; they are the status bits. */ +static inline u16 LM77_TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); + return (u16)((ntemp / 500) * 8); +} + +static inline int LM77_TEMP_FROM_REG(u16 reg) +{ + return ((int)reg / 8) * 500; +} + +/* sysfs stuff */ + +/* read routines for temperature limits */ +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm77_data *data = lm77_update_device(dev); \ + return sprintf(buf, "%d\n", data->value); \ +} + +show(temp_input); +show(temp_crit); +show(temp_min); +show(temp_max); +show(alarms); + +/* read routines for hysteresis values */ +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); +} +static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); +} +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); +} + +/* write routines */ +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm77_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = val; \ + lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ + up(&data->update_lock); \ + return count; \ +} + +set(temp_min, LM77_REG_TEMP_MIN); +set(temp_max, LM77_REG_TEMP_MAX); + +/* hysteresis is stored as a relative value on the chip, so it has to be + converted first */ +static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = data->temp_crit - val; + lm77_write_value(client, LM77_REG_TEMP_HYST, + LM77_TEMP_TO_REG(data->temp_hyst)); + up(&data->update_lock); + return count; +} + +/* preserve hysteresis when setting T_crit */ +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + long val = simple_strtoul(buf, NULL, 10); + int oldcrithyst; + + down(&data->update_lock); + oldcrithyst = data->temp_crit - data->temp_hyst; + data->temp_crit = val; + data->temp_hyst = data->temp_crit - oldcrithyst; + lm77_write_value(client, LM77_REG_TEMP_CRIT, + LM77_TEMP_TO_REG(data->temp_crit)); + lm77_write_value(client, LM77_REG_TEMP_HYST, + LM77_TEMP_TO_REG(data->temp_hyst)); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, + show_temp_input, NULL); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, + show_temp_crit, set_temp_crit); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, + show_temp_min, set_temp_min); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_max, set_temp_max); + +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, + show_temp_crit_hyst, set_temp_crit_hyst); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, + show_temp_min_hyst, NULL); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, + show_temp_max_hyst, NULL); + +static DEVICE_ATTR(alarms, S_IRUGO, + show_alarms, NULL); + +static int lm77_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm77_detect); +} + +/* This function is called by i2c_detect */ +static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm77_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm77_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm77_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm77_driver; + new_client->flags = 0; + + /* Here comes the remaining detection. Since the LM77 has no + register dedicated to identification, we have to rely on the + following tricks: + + 1. the high 4 bits represent the sign and thus they should + always be the same + 2. the high 3 bits are unused in the configuration register + 3. addresses 0x06 and 0x07 return the last read value + 4. registers cycling over 8-address boundaries + + Word-sized registers are high-byte first. */ + if (kind < 0) { + int i, cur, conf, hyst, crit, min, max; + + /* addresses cycling */ + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + crit = i2c_smbus_read_word_data(new_client, 3); + min = i2c_smbus_read_word_data(new_client, 4); + max = i2c_smbus_read_word_data(new_client, 5); + for (i = 8; i <= 0xff; i += 8) + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_word_data(new_client, i + 2) != hyst + || i2c_smbus_read_word_data(new_client, i + 3) != crit + || i2c_smbus_read_word_data(new_client, i + 4) != min + || i2c_smbus_read_word_data(new_client, i + 5) != max) + goto exit_free; + + /* sign bits */ + if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0) + || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0) + || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0) + || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0) + || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0)) + goto exit_free; + + /* unused bits */ + if (conf & 0xe0) + goto exit_free; + + /* 0x06 and 0x07 return the last read value */ + cur = i2c_smbus_read_word_data(new_client, 0); + if (i2c_smbus_read_word_data(new_client, 6) != cur + || i2c_smbus_read_word_data(new_client, 7) != cur) + goto exit_free; + hyst = i2c_smbus_read_word_data(new_client, 2); + if (i2c_smbus_read_word_data(new_client, 6) != hyst + || i2c_smbus_read_word_data(new_client, 7) != hyst) + goto exit_free; + min = i2c_smbus_read_word_data(new_client, 4); + if (i2c_smbus_read_word_data(new_client, 6) != min + || i2c_smbus_read_word_data(new_client, 7) != min) + goto exit_free; + + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm77; + + if (kind == lm77) { + name = "lm77"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM77 chip */ + lm77_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm77_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* All registers are word-sized, except for the configuration register. + The LM77 uses the high-byte first convention. */ +static u16 lm77_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void lm77_init_client(struct i2c_client *client) +{ + /* Initialize the LM77 chip - turn off shutdown mode */ + int conf = lm77_read_value(client, LM77_REG_CONF); + if (conf & 1) + lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); +} + +static struct lm77_data *lm77_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm77 update\n"); + data->temp_input = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP)); + data->temp_hyst = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_HYST)); + data->temp_crit = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_CRIT)); + data->temp_min = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MIN)); + data->temp_max = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MAX)); + data->alarms = + lm77_read_value(client, LM77_REG_TEMP) & 0x0007; + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm77_init(void) +{ + return i2c_add_driver(&lm77_driver); +} + +static void __exit sensors_lm77_exit(void) +{ + i2c_del_driver(&lm77_driver); +} + +MODULE_AUTHOR("Andras BALI "); +MODULE_DESCRIPTION("LM77 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm77_init); +module_exit(sensors_lm77_exit); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c new file mode 100644 index 00000000000..29241469dcb --- /dev/null +++ b/drivers/hwmon/lm78.c @@ -0,0 +1,795 @@ +/* + lm78.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(lm78, lm78j, lm79); + +/* Many LM78 constants specified below */ + +/* Length of ISA address segment */ +#define LM78_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define LM78_ADDR_REG_OFFSET 5 +#define LM78_DATA_REG_OFFSET 6 + +/* The LM78 registers */ +#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define LM78_REG_IN(nr) (0x20 + (nr)) + +#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) +#define LM78_REG_FAN(nr) (0x28 + (nr)) + +#define LM78_REG_TEMP 0x27 +#define LM78_REG_TEMP_OVER 0x39 +#define LM78_REG_TEMP_HYST 0x3a + +#define LM78_REG_ALARM1 0x41 +#define LM78_REG_ALARM2 0x42 + +#define LM78_REG_VID_FANDIV 0x47 + +#define LM78_REG_CONFIG 0x40 +#define LM78_REG_CHIPID 0x49 +#define LM78_REG_I2C_ADDR 0x48 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm <= 0) + return 255; + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-128C to +127C) + REG: 1C/bit, two's complement */ +static inline s8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -128000, 127000) ; + return nval<0 ? (nval-500)/1000 : (nval+500)/1000; +} + +static inline int TEMP_FROM_REG(s8 val) +{ + return val * 1000; +} + +/* VID: mV + REG: (see doc/vid) */ +static inline int VID_FROM_REG(u8 val) +{ + return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; +} + +#define DIV_FROM_REG(val) (1 << (val)) + +/* There are some complications in a module like this. First off, LM78 chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + LM78 chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the LM78 at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered LM78, we need to keep some data in memory. That + data is pointed to by lm78_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm78 client is + allocated. */ +struct lm78_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u16 alarms; /* Register encoding, combined */ +}; + + +static int lm78_attach_adapter(struct i2c_adapter *adapter); +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm78_detach_client(struct i2c_client *client); + +static int lm78_read_value(struct i2c_client *client, u8 register); +static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); +static struct lm78_data *lm78_update_device(struct device *dev); +static void lm78_init_client(struct i2c_client *client); + + +static struct i2c_driver lm78_driver = { + .owner = THIS_MODULE, + .name = "lm78", + .id = I2C_DRIVERID_LM78, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm78_attach_adapter, + .detach_client = lm78_detach_client, +}; + +/* 7 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); +show_in_offset(6); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst); + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long min; + u8 reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + reg = lm78_read_value(client, LM78_REG_VID_FANDIV); + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + lm78_write_value(client, LM78_REG_VID_FANDIV, reg); + + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +/* Fan 3 divisor is locked in H/W */ +static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div); +static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div); +static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); + +/* VID */ +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This function is called when: + * lm78_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm78_driver is still present) */ +static int lm78_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm78_detect); +} + +/* This function is called by i2c_detect */ +int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, err; + struct i2c_client *new_client; + struct lm78_data *data; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -ENODEV; + goto ERROR0; + } + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, LM78_EXTENT, lm78_driver.name)) { + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm78_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct lm78_data)); + + new_client = &data->client; + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm78_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { + err = -ENODEV; + goto ERROR2; + } + if (!is_isa && (lm78_read_value( + new_client, LM78_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = lm78_read_value(new_client, LM78_REG_CHIPID); + if (i == 0x00 || i == 0x20) + kind = lm78; + else if (i == 0x40) + kind = lm78j; + else if ((i & 0xfe) == 0xc0) + kind = lm79; + else { + if (kind == 0) + dev_warn(&adapter->dev, "Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == lm78) { + client_name = "lm78"; + } else if (kind == lm78j) { + client_name = "lm78-j"; + } else if (kind == lm79) { + client_name = "lm79"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + + 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 ERROR2; + + /* Initialize the LM78 chip */ + lm78_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = lm78_read_value(new_client, + LM78_REG_FAN_MIN(i)); + } + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in6_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan3_min); + device_create_file(&new_client->dev, &dev_attr_fan3_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; + +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, LM78_EXTENT); +ERROR0: + return err; +} + +static int lm78_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if(i2c_is_isa_client(client)) + release_region(client->addr, LM78_EXTENT); + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. */ +static int lm78_read_value(struct i2c_client *client, u8 reg) +{ + int res; + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + res = inb_p(client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + outb_p(value, client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM78. It should set limits, etc. */ +static void lm78_init_client(struct i2c_client *client) +{ + u8 config = lm78_read_value(client, LM78_REG_CONFIG); + + /* Start monitoring */ + if (!(config & 0x01)) + lm78_write_value(client, LM78_REG_CONFIG, + (config & 0xf7) | 0x01); +} + +static struct lm78_data *lm78_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting lm78 update\n"); + + for (i = 0; i <= 6; i++) { + data->in[i] = + lm78_read_value(client, LM78_REG_IN(i)); + data->in_min[i] = + lm78_read_value(client, LM78_REG_IN_MIN(i)); + data->in_max[i] = + lm78_read_value(client, LM78_REG_IN_MAX(i)); + } + for (i = 0; i < 3; i++) { + data->fan[i] = + lm78_read_value(client, LM78_REG_FAN(i)); + data->fan_min[i] = + lm78_read_value(client, LM78_REG_FAN_MIN(i)); + } + data->temp = lm78_read_value(client, LM78_REG_TEMP); + data->temp_over = + lm78_read_value(client, LM78_REG_TEMP_OVER); + data->temp_hyst = + lm78_read_value(client, LM78_REG_TEMP_HYST); + i = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->vid = i & 0x0f; + if (data->type == lm79) + data->vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & + 0x01) << 4; + else + data->vid |= 0x10; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + + (lm78_read_value(client, LM78_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + + data->fan_div[2] = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sm_lm78_init(void) +{ + return i2c_add_driver(&lm78_driver); +} + +static void __exit sm_lm78_exit(void) +{ + i2c_del_driver(&lm78_driver); +} + + + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_lm78_init); +module_exit(sm_lm78_exit); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c new file mode 100644 index 00000000000..8100595feb4 --- /dev/null +++ b/drivers/hwmon/lm80.c @@ -0,0 +1,601 @@ +/* + * lm80.c - From lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 1998, 1999 Frodo Looijaard + * and Philip Edelbrock + * + * Ported to Linux 2.6 by Tiago Sousa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm80); + +/* Many LM80 constants specified below */ + +/* The LM80 registers */ +#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) +#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) +#define LM80_REG_IN(nr) (0x20 + (nr)) + +#define LM80_REG_FAN1 0x28 +#define LM80_REG_FAN2 0x29 +#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) + +#define LM80_REG_TEMP 0x27 +#define LM80_REG_TEMP_HOT_MAX 0x38 +#define LM80_REG_TEMP_HOT_HYST 0x39 +#define LM80_REG_TEMP_OS_MAX 0x3a +#define LM80_REG_TEMP_OS_HYST 0x3b + +#define LM80_REG_CONFIG 0x00 +#define LM80_REG_ALARM1 0x01 +#define LM80_REG_ALARM2 0x02 +#define LM80_REG_MASK1 0x03 +#define LM80_REG_MASK2 0x04 +#define LM80_REG_FANDIV 0x05 +#define LM80_REG_RES 0x06 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ + +#define IN_TO_REG(val) (SENSORS_LIMIT(((val)+5)/10,0,255)) +#define IN_FROM_REG(val) ((val)*10) + +static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:\ + (val)==255?0:1350000/((div)*(val))) + +static inline long TEMP_FROM_REG(u16 temp) +{ + long res; + + temp >>= 4; + if (temp < 0x0800) + res = 625 * (long) temp; + else + res = ((long) temp - 0x01000) * 625; + + return res / 10; +} + +#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) + +#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val)<0?\ + ((val)-500)/1000:((val)+500)/1000,0,255) + +#define DIV_FROM_REG(val) (1 << (val)) + +/* + * Client data (each client gets its own) + */ + +struct lm80_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 temp; /* Register values, shifted right */ + u8 temp_hot_max; /* Register value */ + u8 temp_hot_hyst; /* Register value */ + u8 temp_os_max; /* Register value */ + u8 temp_os_hyst; /* Register value */ + u16 alarms; /* Register encoding, combined */ +}; + +/* + * Functions declaration + */ + +static int lm80_attach_adapter(struct i2c_adapter *adapter); +static int lm80_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm80_init_client(struct i2c_client *client); +static int lm80_detach_client(struct i2c_client *client); +static struct lm80_data *lm80_update_device(struct device *dev); +static int lm80_read_value(struct i2c_client *client, u8 reg); +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm80_driver = { + .owner = THIS_MODULE, + .name = "lm80", + .id = I2C_DRIVERID_LM80, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm80_attach_adapter, + .detach_client = lm80_detach_client, +}; + +/* + * Sysfs stuff + */ + +#define show_in(suffix, value) \ +static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ +} +show_in(min0, in_min[0]); +show_in(min1, in_min[1]); +show_in(min2, in_min[2]); +show_in(min3, in_min[3]); +show_in(min4, in_min[4]); +show_in(min5, in_min[5]); +show_in(min6, in_min[6]); +show_in(max0, in_max[0]); +show_in(max1, in_max[1]); +show_in(max2, in_max[2]); +show_in(max3, in_max[3]); +show_in(max4, in_max[4]); +show_in(max5, in_max[5]); +show_in(max6, in_max[6]); +show_in(input0, in[0]); +show_in(input1, in[1]); +show_in(input2, in[2]); +show_in(input3, in[3]); +show_in(input4, in[4]); +show_in(input5, in[5]); +show_in(input6, in[6]); + +#define set_in(suffix, value, reg) \ +static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock);\ + data->value = IN_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock);\ + return count; \ +} +set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); +set_in(min1, in_min[1], LM80_REG_IN_MIN(1)); +set_in(min2, in_min[2], LM80_REG_IN_MIN(2)); +set_in(min3, in_min[3], LM80_REG_IN_MIN(3)); +set_in(min4, in_min[4], LM80_REG_IN_MIN(4)); +set_in(min5, in_min[5], LM80_REG_IN_MIN(5)); +set_in(min6, in_min[6], LM80_REG_IN_MIN(6)); +set_in(max0, in_max[0], LM80_REG_IN_MAX(0)); +set_in(max1, in_max[1], LM80_REG_IN_MAX(1)); +set_in(max2, in_max[2], LM80_REG_IN_MAX(2)); +set_in(max3, in_max[3], LM80_REG_IN_MAX(3)); +set_in(max4, in_max[4], LM80_REG_IN_MAX(4)); +set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); +set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); + +#define show_fan(suffix, value, div) \ +static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ + DIV_FROM_REG(data->div))); \ +} +show_fan(min1, fan_min[0], fan_div[0]); +show_fan(min2, fan_min[1], fan_div[1]); +show_fan(input1, fan[0], fan_div[0]); +show_fan(input2, fan[1], fan_div[1]); + +#define show_fan_div(suffix, value) \ +static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ +} +show_fan_div(1, fan_div[0]); +show_fan_div(2, fan_div[1]); + +#define set_fan(suffix, value, reg, div) \ +static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock);\ + data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock);\ + return count; \ +} +set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); +set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + unsigned long min, val = simple_strtoul(buf, NULL, 10); + u8 reg; + + /* Save fan_min */ + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) + | (data->fan_div[nr] << (2 * (nr + 1))); + lm80_write_value(client, LM80_REG_FANDIV, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define set_fan_div(number) \ +static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, number - 1); \ +} +set_fan_div(1); +set_fan_div(2); + +static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); +} + +#define show_temp(suffix, value) \ +static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ +} +show_temp(hot_max, temp_hot_max); +show_temp(hot_hyst, temp_hot_hyst); +show_temp(os_max, temp_os_max); +show_temp(os_hyst, temp_os_hyst); + +#define set_temp(suffix, value, reg) \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_LIMIT_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); +set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); +set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); +set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); +static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1); +static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2); +static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3); +static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4); +static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5); +static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6); +static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0); +static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1); +static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2); +static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3); +static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4); +static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5); +static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6); +static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); +static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); +static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL); +static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL); +static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL); +static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, + set_fan_min1); +static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, + set_fan_min2); +static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); +static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); +static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); +static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, + set_temp_hot_max); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, + set_temp_hot_hyst); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, + set_temp_os_max); +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, + set_temp_os_hyst); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm80_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm80_detect); +} + +int lm80_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, cur; + struct i2c_client *new_client; + struct lm80_data *data; + int err = 0; + const char *name; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm80_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm80_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm80_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. It is lousy. */ + if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) + goto error_free; + for (i = 0x2a; i <= 0x3d; i++) { + cur = i2c_smbus_read_byte_data(new_client, i); + if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) + || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) + || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) + goto error_free; + } + + /* Determine the chip type - only one kind supported! */ + kind = lm80; + name = "lm80"; + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, 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 error_free; + + /* Initialize the LM80 chip */ + lm80_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); + data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_max); + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(data); +exit: + return err; +} + +static int lm80_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 lm80_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM80. */ +static void lm80_init_client(struct i2c_client *client) +{ + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others. This makes most other + initializations unnecessary */ + lm80_write_value(client, LM80_REG_CONFIG, 0x80); + /* Set 11-bit temperature resolution */ + lm80_write_value(client, LM80_REG_RES, 0x08); + + /* Start monitoring */ + lm80_write_value(client, LM80_REG_CONFIG, 0x01); +} + +static struct lm80_data *lm80_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(&client->dev, "Starting lm80 update\n"); + for (i = 0; i <= 6; i++) { + data->in[i] = + lm80_read_value(client, LM80_REG_IN(i)); + data->in_min[i] = + lm80_read_value(client, LM80_REG_IN_MIN(i)); + data->in_max[i] = + lm80_read_value(client, LM80_REG_IN_MAX(i)); + } + data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); + data->fan_min[0] = + lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); + data->fan_min[1] = + lm80_read_value(client, LM80_REG_FAN_MIN(2)); + + data->temp = + (lm80_read_value(client, LM80_REG_TEMP) << 8) | + (lm80_read_value(client, LM80_REG_RES) & 0xf0); + data->temp_os_max = + lm80_read_value(client, LM80_REG_TEMP_OS_MAX); + data->temp_os_hyst = + lm80_read_value(client, LM80_REG_TEMP_OS_HYST); + data->temp_hot_max = + lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); + data->temp_hot_hyst = + lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); + + i = lm80_read_value(client, LM80_REG_FANDIV); + data->fan_div[0] = (i >> 2) & 0x03; + data->fan_div[1] = (i >> 4) & 0x03; + data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + + (lm80_read_value(client, LM80_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm80_init(void) +{ + return i2c_add_driver(&lm80_driver); +} + +static void __exit sensors_lm80_exit(void) +{ + i2c_del_driver(&lm80_driver); +} + +MODULE_AUTHOR("Frodo Looijaard and " + "Philip Edelbrock "); +MODULE_DESCRIPTION("LM80 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm80_init); +module_exit(sensors_lm80_exit); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c new file mode 100644 index 00000000000..a49008b444c --- /dev/null +++ b/drivers/hwmon/lm83.c @@ -0,0 +1,408 @@ +/* + * lm83.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2005 Jean Delvare + * + * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is + * a sensor chip made by National Semiconductor. It reports up to four + * temperatures (its own plus up to three external ones) with a 1 deg + * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained + * from National's website at: + * http://www.national.com/pf/LM/LM83.html + * Since the datasheet omits to give the chip stepping code, I give it + * here: 0x03 (at register 0xff). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is selected using 2 three-level pins, resulting in 9 possible + * addresses. + */ + +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm83); + +/* + * The LM83 registers + * Manufacturer ID is 0x01 for National Semiconductor. + */ + +#define LM83_REG_R_MAN_ID 0xFE +#define LM83_REG_R_CHIP_ID 0xFF +#define LM83_REG_R_CONFIG 0x03 +#define LM83_REG_W_CONFIG 0x09 +#define LM83_REG_R_STATUS1 0x02 +#define LM83_REG_R_STATUS2 0x35 +#define LM83_REG_R_LOCAL_TEMP 0x00 +#define LM83_REG_R_LOCAL_HIGH 0x05 +#define LM83_REG_W_LOCAL_HIGH 0x0B +#define LM83_REG_R_REMOTE1_TEMP 0x30 +#define LM83_REG_R_REMOTE1_HIGH 0x38 +#define LM83_REG_W_REMOTE1_HIGH 0x50 +#define LM83_REG_R_REMOTE2_TEMP 0x01 +#define LM83_REG_R_REMOTE2_HIGH 0x07 +#define LM83_REG_W_REMOTE2_HIGH 0x0D +#define LM83_REG_R_REMOTE3_TEMP 0x31 +#define LM83_REG_R_REMOTE3_HIGH 0x3A +#define LM83_REG_W_REMOTE3_HIGH 0x52 +#define LM83_REG_R_TCRIT 0x42 +#define LM83_REG_W_TCRIT 0x5A + +/* + * Conversions and various macros + * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. + */ + +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) + +static const u8 LM83_REG_R_TEMP[] = { + LM83_REG_R_LOCAL_TEMP, + LM83_REG_R_REMOTE1_TEMP, + LM83_REG_R_REMOTE2_TEMP, + LM83_REG_R_REMOTE3_TEMP, + LM83_REG_R_LOCAL_HIGH, + LM83_REG_R_REMOTE1_HIGH, + LM83_REG_R_REMOTE2_HIGH, + LM83_REG_R_REMOTE3_HIGH, + LM83_REG_R_TCRIT, +}; + +static const u8 LM83_REG_W_HIGH[] = { + LM83_REG_W_LOCAL_HIGH, + LM83_REG_W_REMOTE1_HIGH, + LM83_REG_W_REMOTE2_HIGH, + LM83_REG_W_REMOTE3_HIGH, + LM83_REG_W_TCRIT, +}; + +/* + * Functions declaration + */ + +static int lm83_attach_adapter(struct i2c_adapter *adapter); +static int lm83_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm83_detach_client(struct i2c_client *client); +static struct lm83_data *lm83_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm83_driver = { + .owner = THIS_MODULE, + .name = "lm83", + .id = I2C_DRIVERID_LM83, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm83_attach_adapter, + .detach_client = lm83_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm83_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + s8 temp[9]; /* 0..3: input 1-4, + 4..7: high limit 1-4, + 8 : critical limit */ + u16 alarms; /* bitvector, combined */ +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], + data->temp[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 4); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 5); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 6); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 7); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, 8); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm83_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm83_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm83_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm83_data)); + + /* The common I2C client data is placed right after the + * LM83-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm83_driver; + new_client->flags = 0; + + /* Now we do the detection and identification. A negative kind + * means that the driver was loaded with no force parameter + * (default), so we must both detect and identify the chip + * (actually there is only one possible kind of chip for now, LM83). + * A zero kind means that the driver was loaded with the force + * parameter, the detection step shall be skipped. A positive kind + * means that the driver was loaded with the force parameter and a + * given kind of chip is requested, so both the detection and the + * identification steps are skipped. */ + + /* Default to an LM83 if forced */ + if (kind == 0) + kind = lm83; + + if (kind < 0) { /* detection */ + if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) + & 0xA8) != 0x00) || + ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) + & 0x48) != 0x00) || + ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) + & 0x41) != 0x00)) { + dev_dbg(&adapter->dev, + "LM83 detection failed at 0x%02x.\n", address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u8 man_id, chip_id; + + man_id = i2c_smbus_read_byte_data(new_client, + LM83_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM83_REG_R_CHIP_ID); + + if (man_id == 0x01) { /* National Semiconductor */ + if (chip_id == 0x03) { + kind = lm83; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == lm83) { + name = "lm83"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* + * Initialize the LM83 chip + * (Nothing to do for this one.) + */ + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm83_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 struct lm83_data *lm83_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int nr; + + dev_dbg(&client->dev, "Updating lm83 data.\n"); + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = + i2c_smbus_read_byte_data(client, + LM83_REG_R_TEMP[nr]); + } + data->alarms = + i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) + << 8); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm83_init(void) +{ + return i2c_add_driver(&lm83_driver); +} + +static void __exit sensors_lm83_exit(void) +{ + i2c_del_driver(&lm83_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM83 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm83_init); +module_exit(sensors_lm83_exit); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c new file mode 100644 index 00000000000..b4d7fd41826 --- /dev/null +++ b/drivers/hwmon/lm85.c @@ -0,0 +1,1575 @@ +/* + lm85.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (c) 2002, 2003 Philip Pokorny + Copyright (c) 2003 Margit Schubert-While + Copyright (c) 2004 Justin Thiessen + + Chip details at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); + +/* The LM85 registers */ + +#define LM85_REG_IN(nr) (0x20 + (nr)) +#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) +#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) + +#define LM85_REG_TEMP(nr) (0x25 + (nr)) +#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) +#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) + +/* Fan speeds are LSB, MSB (2 bytes) */ +#define LM85_REG_FAN(nr) (0x28 + (nr) *2) +#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) + +#define LM85_REG_PWM(nr) (0x30 + (nr)) + +#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) + +#define ADT7463_REG_TMIN_CTL1 0x36 +#define ADT7463_REG_TMIN_CTL2 0x37 + +#define LM85_REG_DEVICE 0x3d +#define LM85_REG_COMPANY 0x3e +#define LM85_REG_VERSTEP 0x3f +/* These are the recognized values for the above regs */ +#define LM85_DEVICE_ADX 0x27 +#define LM85_COMPANY_NATIONAL 0x01 +#define LM85_COMPANY_ANALOG_DEV 0x41 +#define LM85_COMPANY_SMSC 0x5c +#define LM85_VERSTEP_VMASK 0xf0 +#define LM85_VERSTEP_GENERIC 0x60 +#define LM85_VERSTEP_LM85C 0x60 +#define LM85_VERSTEP_LM85B 0x62 +#define LM85_VERSTEP_ADM1027 0x60 +#define LM85_VERSTEP_ADT7463 0x62 +#define LM85_VERSTEP_ADT7463C 0x6A +#define LM85_VERSTEP_EMC6D100_A0 0x60 +#define LM85_VERSTEP_EMC6D100_A1 0x61 +#define LM85_VERSTEP_EMC6D102 0x65 + +#define LM85_REG_CONFIG 0x40 + +#define LM85_REG_ALARM1 0x41 +#define LM85_REG_ALARM2 0x42 + +#define LM85_REG_VID 0x43 + +/* Automated FAN control */ +#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) +#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) +#define LM85_REG_AFAN_SPIKE1 0x62 +#define LM85_REG_AFAN_SPIKE2 0x63 +#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) +#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) +#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) +#define LM85_REG_AFAN_HYST1 0x6d +#define LM85_REG_AFAN_HYST2 0x6e + +#define LM85_REG_TACH_MODE 0x74 +#define LM85_REG_SPINUP_CTL 0x75 + +#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) +#define ADM1027_REG_CONFIG2 0x73 +#define ADM1027_REG_INTMASK1 0x74 +#define ADM1027_REG_INTMASK2 0x75 +#define ADM1027_REG_EXTEND_ADC1 0x76 +#define ADM1027_REG_EXTEND_ADC2 0x77 +#define ADM1027_REG_CONFIG3 0x78 +#define ADM1027_REG_FAN_PPR 0x7b + +#define ADT7463_REG_THERM 0x79 +#define ADT7463_REG_THERM_LIMIT 0x7A + +#define EMC6D100_REG_ALARM3 0x7d +/* IN5, IN6 and IN7 */ +#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) +#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) +#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) +#define EMC6D102_REG_EXTEND_ADC1 0x85 +#define EMC6D102_REG_EXTEND_ADC2 0x86 +#define EMC6D102_REG_EXTEND_ADC3 0x87 +#define EMC6D102_REG_EXTEND_ADC4 0x88 + +#define LM85_ALARM_IN0 0x0001 +#define LM85_ALARM_IN1 0x0002 +#define LM85_ALARM_IN2 0x0004 +#define LM85_ALARM_IN3 0x0008 +#define LM85_ALARM_TEMP1 0x0010 +#define LM85_ALARM_TEMP2 0x0020 +#define LM85_ALARM_TEMP3 0x0040 +#define LM85_ALARM_ALARM2 0x0080 +#define LM85_ALARM_IN4 0x0100 +#define LM85_ALARM_RESERVED 0x0200 +#define LM85_ALARM_FAN1 0x0400 +#define LM85_ALARM_FAN2 0x0800 +#define LM85_ALARM_FAN3 0x1000 +#define LM85_ALARM_FAN4 0x2000 +#define LM85_ALARM_TEMP1_FAULT 0x4000 +#define LM85_ALARM_TEMP3_FAULT 0x8000 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled acording to built-in resistors */ +static int lm85_scaling[] = { /* .001 Volts */ + 2500, 2250, 3300, 5000, 12000, + 3300, 1500, 1800 /*EMC6D100*/ + }; +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) + +#define INS_TO_REG(n,val) \ + SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) + +#define INSEXT_FROM_REG(n,val,ext,scale) \ + SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) + +#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) + +/* FAN speed is measured using 90kHz clock */ +#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) +#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) + +/* Temperature is reported in .001 degC increments */ +#define TEMP_TO_REG(val) \ + SENSORS_LIMIT(SCALE(val,1000,1),-127,127) +#define TEMPEXT_FROM_REG(val,ext,scale) \ + SCALE((val)*scale + (ext),scale,1000) +#define TEMP_FROM_REG(val) \ + TEMPEXT_FROM_REG(val,0,1) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + + +/* ZONEs have the following parameters: + * Limit (low) temp, 1. degC + * Hysteresis (below limit), 1. degC (0-15) + * Range of speed control, .1 degC (2-80) + * Critical (high) temp, 1. degC + * + * FAN PWMs have the following parameters: + * Reference Zone, 1, 2, 3, etc. + * Spinup time, .05 sec + * PWM value at limit/low temp, 1 count + * PWM Frequency, 1. Hz + * PWM is Min or OFF below limit, flag + * Invert PWM output, flag + * + * Some chips filter the temp, others the fan. + * Filter constant (or disabled) .1 seconds + */ + +/* These are the zone temperature range encodings in .001 degree C */ +static int lm85_range_map[] = { + 2000, 2500, 3300, 4000, 5000, 6600, + 8000, 10000, 13300, 16000, 20000, 26600, + 32000, 40000, 53300, 80000 + }; +static int RANGE_TO_REG( int range ) +{ + int i; + + if ( range < lm85_range_map[0] ) { + return 0 ; + } else if ( range > lm85_range_map[15] ) { + return 15 ; + } else { /* find closest match */ + for ( i = 14 ; i >= 0 ; --i ) { + if ( range > lm85_range_map[i] ) { /* range bracketed */ + if ((lm85_range_map[i+1] - range) < + (range - lm85_range_map[i])) { + i++; + break; + } + break; + } + } + } + return( i & 0x0f ); +} +#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) + +/* These are the Acoustic Enhancement, or Temperature smoothing encodings + * NOTE: The enable/disable bit is INCLUDED in these encodings as the + * MSB (bit 3, value 8). If the enable bit is 0, the encoded value + * is ignored, or set to 0. + */ +/* These are the PWM frequency encodings */ +static int lm85_freq_map[] = { /* .1 Hz */ + 100, 150, 230, 300, 380, 470, 620, 940 + }; +static int FREQ_TO_REG( int freq ) +{ + int i; + + if( freq >= lm85_freq_map[7] ) { return 7 ; } + for( i = 0 ; i < 7 ; ++i ) + if( freq <= lm85_freq_map[i] ) + break ; + return( i & 0x07 ); +} +#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) + +/* Since we can't use strings, I'm abusing these numbers + * to stand in for the following meanings: + * 1 -- PWM responds to Zone 1 + * 2 -- PWM responds to Zone 2 + * 3 -- PWM responds to Zone 3 + * 23 -- PWM responds to the higher temp of Zone 2 or 3 + * 123 -- PWM responds to highest of Zone 1, 2, or 3 + * 0 -- PWM is always at 0% (ie, off) + * -1 -- PWM is always at 100% + * -2 -- PWM responds to manual control + */ + +static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; +#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) + +static int ZONE_TO_REG( int zone ) +{ + int i; + + for( i = 0 ; i <= 7 ; ++i ) + if( zone == lm85_zone_map[i] ) + break ; + if( i > 7 ) /* Not found. */ + i = 3; /* Always 100% */ + return( (i & 0x07)<<5 ); +} + +#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) +#define HYST_FROM_REG(val) ((val)*1000) + +#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define OFFSET_FROM_REG(val) ((val)*25) + +#define PPR_MASK(fan) (0x03<<(fan *2)) +#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) +#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) + +/* i2c-vid.h defines vid_from_reg() */ +#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) + +/* Unlike some other drivers we DO NOT set initial limits. Use + * the config file to set limits. Some users have reported + * motherboards shutting down when we set limits in a previous + * version of the driver. + */ + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * given the automatic PWM fan control that is possible. There + * are about 47 bytes of config data to only 22 bytes of actual + * readings. So, we keep the config data up to date in the cache + * when it is written and only sample it once every 1 *minute* + */ +#define LM85_DATA_INTERVAL (HZ + HZ / 2) +#define LM85_CONFIG_INTERVAL (1 * 60 * HZ) + +/* For each registered LM85, we need to keep some data in memory. That + data is pointed to by lm85_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm85 client is + allocated. */ + +/* LM85 can automatically adjust fan speeds based on temperature + * This structure encapsulates an entire Zone config. There are + * three zones (one for each temperature input) on the lm85 + */ +struct lm85_zone { + s8 limit; /* Low temp limit */ + u8 hyst; /* Low limit hysteresis. (0-15) */ + u8 range; /* Temp range, encoded */ + s8 critical; /* "All fans ON" temp limit */ + u8 off_desired; /* Actual "off" temperature specified. Preserved + * to prevent "drift" as other autofan control + * values change. + */ + u8 max_desired; /* Actual "max" temperature specified. Preserved + * to prevent "drift" as other autofan control + * values change. + */ +}; + +struct lm85_autofan { + u8 config; /* Register value */ + u8 freq; /* PWM frequency, encoded */ + u8 min_pwm; /* Minimum PWM value, encoded */ + u8 min_off; /* Min PWM or OFF below "limit", flag */ +}; + +struct lm85_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[8]; /* Register value */ + u8 in_max[8]; /* Register value */ + u8 in_min[8]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u16 fan[4]; /* Register value */ + u16 fan_min[4]; /* Register value */ + u8 pwm[3]; /* Register value */ + u8 spinup_ctl; /* Register encoding, combined */ + u8 tach_mode; /* Register encoding, combined */ + u8 temp_ext[3]; /* Decoded values */ + u8 in_ext[8]; /* Decoded values */ + u8 adc_scale; /* ADC Extended bits scaling factor */ + u8 fan_ppr; /* Register value */ + u8 smooth[3]; /* Register encoding */ + u8 vid; /* Register value */ + u8 vrm; /* VRM version */ + u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ + u8 oppoint[3]; /* Register value */ + u16 tmin_ctl; /* Register value */ + unsigned long therm_total; /* Cummulative therm count */ + u8 therm_limit; /* Register value */ + u32 alarms; /* Register encoding, combined */ + struct lm85_autofan autofan[3]; + struct lm85_zone zone[3]; +}; + +static int lm85_attach_adapter(struct i2c_adapter *adapter); +static int lm85_detect(struct i2c_adapter *adapter, int address, + int kind); +static int lm85_detach_client(struct i2c_client *client); + +static int lm85_read_value(struct i2c_client *client, u8 register); +static int lm85_write_value(struct i2c_client *client, u8 register, int value); +static struct lm85_data *lm85_update_device(struct device *dev); +static void lm85_init_client(struct i2c_client *client); + + +static struct i2c_driver lm85_driver = { + .owner = THIS_MODULE, + .name = "lm85", + .id = I2C_DRIVERID_LM85, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm85_attach_adapter, + .detach_client = lm85_detach_client, +}; + + +/* 4 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); +} +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val); + lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); +show_fan_offset(4); + +/* vid, vrm, alarms */ + +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); + +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + return count; +} + +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); + +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + +/* pwm */ + +static ssize_t show_pwm(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); +} +static ssize_t set_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm[nr] = PWM_TO_REG(val); + lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + int pwm_zone; + + pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); + return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) ); +} + +#define show_pwm_reg(offset) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_enable(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset); \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ + show_pwm_enable##offset, NULL); + +show_pwm_reg(1); +show_pwm_reg(2); +show_pwm_reg(3); + +/* Voltages */ + +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, + data->in[nr], + data->in_ext[nr], + data->adc_scale) ); +} +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); +} +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = INS_TO_REG(nr, val); + lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); +} +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = INS_TO_REG(nr, val); + lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} +#define show_in_reg(offset) \ +static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ + NULL); \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_##offset##_min, set_in_##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_##offset##_max, set_in_##offset##_max); + +show_in_reg(0); +show_in_reg(1); +show_in_reg(2); +show_in_reg(3); +show_in_reg(4); + +/* Temps */ + +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], + data->temp_ext[nr], + data->adc_scale) ); +} +static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); +} +static ssize_t set_temp_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); +} +static ssize_t set_temp_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_reg(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_max(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ + NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_min, set_temp_##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_max, set_temp_##offset##_max); + +show_temp_reg(1); +show_temp_reg(2); +show_temp_reg(3); + + +/* Automatic PWM control */ + +static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); +} +static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) + | ZONE_TO_REG(val) ; + lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), + data->autofan[nr].config); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); +} +static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].min_pwm = PWM_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), + data->autofan[nr].min_pwm); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", data->autofan[nr].min_off); +} +static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].min_off = val; + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] + | data->syncpwm3 + | (data->autofan[0].min_off ? 0x20 : 0) + | (data->autofan[1].min_off ? 0x40 : 0) + | (data->autofan[2].min_off ? 0x80 : 0) + ); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); +} +static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].freq = FREQ_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + (data->zone[nr].range << 4) + | data->autofan[nr].freq + ); + up(&data->update_lock); + return count; +} +#define pwm_auto(offset) \ +static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_channels(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_channels(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_channels, \ + set_pwm##offset##_auto_channels); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_min, \ + set_pwm##offset##_auto_pwm_min); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_minctl, \ + set_pwm##offset##_auto_pwm_minctl); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_freq, \ + set_pwm##offset##_auto_pwm_freq); +pwm_auto(1); +pwm_auto(2); +pwm_auto(3); + +/* Temperature settings for automatic PWM control */ + +static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - + HYST_FROM_REG(data->zone[nr].hyst)); +} +static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int min; + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + min = TEMP_FROM_REG(data->zone[nr].limit); + data->zone[nr].off_desired = TEMP_TO_REG(val); + data->zone[nr].hyst = HYST_TO_REG(min - val); + if ( nr == 0 || nr == 1 ) { + lm85_write_value(client, LM85_REG_AFAN_HYST1, + (data->zone[0].hyst << 4) + | data->zone[1].hyst + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_HYST2, + (data->zone[2].hyst << 4) + ); + } + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); +} +static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->zone[nr].limit = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), + data->zone[nr].limit); + +/* Update temp_auto_max and temp_auto_range */ + data->zone[nr].range = RANGE_TO_REG( + TEMP_FROM_REG(data->zone[nr].max_desired) - + TEMP_FROM_REG(data->zone[nr].limit)); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + ((data->zone[nr].range & 0x0f) << 4) + | (data->autofan[nr].freq & 0x07)); + +/* Update temp_auto_hyst and temp_auto_off */ + data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG( + data->zone[nr].limit) - TEMP_FROM_REG( + data->zone[nr].off_desired)); + if ( nr == 0 || nr == 1 ) { + lm85_write_value(client, LM85_REG_AFAN_HYST1, + (data->zone[0].hyst << 4) + | data->zone[1].hyst + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_HYST2, + (data->zone[2].hyst << 4) + ); + } + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + + RANGE_FROM_REG(data->zone[nr].range)); +} +static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int min; + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + min = TEMP_FROM_REG(data->zone[nr].limit); + data->zone[nr].max_desired = TEMP_TO_REG(val); + data->zone[nr].range = RANGE_TO_REG( + val - min); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + ((data->zone[nr].range & 0x0f) << 4) + | (data->autofan[nr].freq & 0x07)); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); +} +static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->zone[nr].critical = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), + data->zone[nr].critical); + up(&data->update_lock); + return count; +} +#define temp_auto(offset) \ +static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_off(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_crit(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_off, \ + set_temp##offset##_auto_temp_off); \ +static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_min, \ + set_temp##offset##_auto_temp_min); \ +static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_max, \ + set_temp##offset##_auto_temp_max); \ +static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_crit, \ + set_temp##offset##_auto_temp_crit); +temp_auto(1); +temp_auto(2); +temp_auto(3); + +int lm85_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm85_detect); +} + +int lm85_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int company, verstep ; + struct i2c_client *new_client = NULL; + struct lm85_data *data; + int err = 0; + const char *type_name = ""; + + if (i2c_is_isa_adapter(adapter)) { + /* This chip has no ISA interface */ + goto ERROR0 ; + }; + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto ERROR0 ; + }; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm85_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct lm85_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm85_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = lm85_read_value(new_client, LM85_REG_COMPANY); + verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); + + dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep); + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { + dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", + i2c_adapter_id(adapter), address ); + if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85C ) { + kind = lm85c ; + } else if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85B ) { + kind = lm85b ; + } else if( company == LM85_COMPANY_NATIONAL + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" + " Defaulting to LM85.\n", verstep); + kind = any_chip ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && verstep == LM85_VERSTEP_ADM1027 ) { + kind = adm1027 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && (verstep == LM85_VERSTEP_ADT7463 + || verstep == LM85_VERSTEP_ADT7463C) ) { + kind = adt7463 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( company == LM85_COMPANY_SMSC + && (verstep == LM85_VERSTEP_EMC6D100_A0 + || verstep == LM85_VERSTEP_EMC6D100_A1) ) { + /* Unfortunately, we can't tell a '100 from a '101 + * from the registers. Since a '101 is a '100 + * in a package with fewer pins and therefore no + * 3.3V, 1.5V or 1.8V inputs, perhaps if those + * inputs read 0, then it's a '101. + */ + kind = emc6d100 ; + } else if( company == LM85_COMPANY_SMSC + && verstep == LM85_VERSTEP_EMC6D102) { + kind = emc6d102 ; + } else if( company == LM85_COMPANY_SMSC + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + dev_err(&adapter->dev, "lm85: Detected SMSC chip\n"); + dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( kind == any_chip + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); + /* Leave kind as "any_chip" */ + } else { + dev_dbg(&adapter->dev, "Autodetection failed\n"); + /* Not an LM85 ... */ + if( kind == any_chip ) { /* User used force=x,y */ + dev_err(&adapter->dev, "Generic LM85 Version 6 not" + " found at %d,0x%02x. Try force_lm85c.\n", + i2c_adapter_id(adapter), address ); + } + err = 0 ; + goto ERROR1; + } + } + + /* Fill in the chip specific driver values */ + if ( kind == any_chip ) { + type_name = "lm85"; + } else if ( kind == lm85b ) { + type_name = "lm85b"; + } else if ( kind == lm85c ) { + type_name = "lm85c"; + } else if ( kind == adm1027 ) { + type_name = "adm1027"; + } else if ( kind == adt7463 ) { + type_name = "adt7463"; + } else if ( kind == emc6d100){ + type_name = "emc6d100"; + } else if ( kind == emc6d102 ) { + type_name = "emc6d102"; + } + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + + /* Fill in the remaining client fields */ + data->type = kind; + 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 ERROR1; + + /* Set the VRM version */ + data->vrm = i2c_which_vrm(); + + /* Initialize the LM85 chip */ + lm85_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan4_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan3_min); + device_create_file(&new_client->dev, &dev_attr_fan4_min); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + device_create_file(&new_client->dev, &dev_attr_pwm3_enable); + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit); + + return 0; + + /* Error out and cleanup code */ + ERROR1: + kfree(data); + ERROR0: + return err; +} + +int lm85_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + + +int lm85_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + /* What size location is it? */ + switch( reg ) { + case LM85_REG_FAN(0) : /* Read WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + case LM85_REG_ALARM1 : /* Read both bytes at once */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff ; + res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ; + break ; + case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */ + res = i2c_smbus_read_byte_data(client, reg) << 8 ; + res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; + break ; + default: /* Read BYTE data */ + res = i2c_smbus_read_byte_data(client, reg); + break ; + } + + return res ; +} + +int lm85_write_value(struct i2c_client *client, u8 reg, int value) +{ + int res ; + + switch( reg ) { + case LM85_REG_FAN(0) : /* Write WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + /* NOTE: ALARM is read only, so not included here */ + res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; + res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; + break ; + case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */ + res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); + res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; + break ; + default: /* Write BYTE data */ + res = i2c_smbus_write_byte_data(client, reg, value); + break ; + } + + return res ; +} + +void lm85_init_client(struct i2c_client *client) +{ + int value; + struct lm85_data *data = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "Initializing device\n"); + + /* Warn if part was not "READY" */ + value = lm85_read_value(client, LM85_REG_CONFIG); + dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); + if( value & 0x02 ) { + dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + if( ! (value & 0x04) ) { + dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + if( value & 0x10 + && ( data->type == adm1027 + || data->type == adt7463 ) ) { + dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " + "Please report this to the lm85 maintainer.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms, fans and zones. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is 100% PWM, no + * control and will suffice until 'sensors -s' + * can be run by the user. + */ + + /* Start monitoring */ + value = lm85_read_value(client, LM85_REG_CONFIG); + /* Try to clear LOCK, Set START, save everything else */ + value = (value & ~ 0x02) | 0x01 ; + dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); + lm85_write_value(client, LM85_REG_CONFIG, value); +} + +static struct lm85_data *lm85_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if ( !data->valid || + time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { + /* Things that change quickly */ + dev_dbg(&client->dev, "Reading sensor values\n"); + + /* Have to read extended bits first to "freeze" the + * more significant bits that are read later. + */ + if ( (data->type == adm1027) || (data->type == adt7463) ) { + int ext1 = lm85_read_value(client, + ADM1027_REG_EXTEND_ADC1); + int ext2 = lm85_read_value(client, + ADM1027_REG_EXTEND_ADC2); + int val = (ext1 << 8) + ext2; + + for(i = 0; i <= 4; i++) + data->in_ext[i] = (val>>(i * 2))&0x03; + + for(i = 0; i <= 2; i++) + data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; + } + + /* adc_scale is 2^(number of LSBs). There are 4 extra bits in + the emc6d102 and 2 in the adt7463 and adm1027. In all + other chips ext is always 0 and the value of scale is + irrelevant. So it is left in 4*/ + data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; + + for (i = 0; i <= 4; ++i) { + data->in[i] = + lm85_read_value(client, LM85_REG_IN(i)); + } + + for (i = 0; i <= 3; ++i) { + data->fan[i] = + lm85_read_value(client, LM85_REG_FAN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp[i] = + lm85_read_value(client, LM85_REG_TEMP(i)); + } + + for (i = 0; i <= 2; ++i) { + data->pwm[i] = + lm85_read_value(client, LM85_REG_PWM(i)); + } + + data->alarms = lm85_read_value(client, LM85_REG_ALARM1); + + if ( data->type == adt7463 ) { + if( data->therm_total < ULONG_MAX - 256 ) { + data->therm_total += + lm85_read_value(client, ADT7463_REG_THERM ); + } + } else if ( data->type == emc6d100 ) { + /* Three more voltage sensors */ + for (i = 5; i <= 7; ++i) { + data->in[i] = + lm85_read_value(client, EMC6D100_REG_IN(i)); + } + /* More alarm bits */ + data->alarms |= + lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; + } else if (data->type == emc6d102 ) { + /* Have to read LSB bits after the MSB ones because + the reading of the MSB bits has frozen the + LSBs (backward from the ADM1027). + */ + int ext1 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC1); + int ext2 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC2); + int ext3 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC3); + int ext4 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC4); + data->in_ext[0] = ext3 & 0x0f; + data->in_ext[1] = ext4 & 0x0f; + data->in_ext[2] = (ext4 >> 4) & 0x0f; + data->in_ext[3] = (ext3 >> 4) & 0x0f; + data->in_ext[4] = (ext2 >> 4) & 0x0f; + + data->temp_ext[0] = ext1 & 0x0f; + data->temp_ext[1] = ext2 & 0x0f; + data->temp_ext[2] = (ext1 >> 4) & 0x0f; + } + + data->last_reading = jiffies ; + }; /* last_reading */ + + if ( !data->valid || + time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { + /* Things that don't change often */ + dev_dbg(&client->dev, "Reading config values\n"); + + for (i = 0; i <= 4; ++i) { + data->in_min[i] = + lm85_read_value(client, LM85_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, LM85_REG_IN_MAX(i)); + } + + if ( data->type == emc6d100 ) { + for (i = 5; i <= 7; ++i) { + data->in_min[i] = + lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); + } + } + + for (i = 0; i <= 3; ++i) { + data->fan_min[i] = + lm85_read_value(client, LM85_REG_FAN_MIN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp_min[i] = + lm85_read_value(client, LM85_REG_TEMP_MIN(i)); + data->temp_max[i] = + lm85_read_value(client, LM85_REG_TEMP_MAX(i)); + } + + data->vid = lm85_read_value(client, LM85_REG_VID); + + for (i = 0; i <= 2; ++i) { + int val ; + data->autofan[i].config = + lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); + val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); + data->autofan[i].freq = val & 0x07 ; + data->zone[i].range = (val >> 4) & 0x0f ; + data->autofan[i].min_pwm = + lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); + data->zone[i].limit = + lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); + data->zone[i].critical = + lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); + } + + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); + data->smooth[0] = i & 0x0f ; + data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ + data->autofan[0].min_off = (i & 0x20) != 0 ; + data->autofan[1].min_off = (i & 0x40) != 0 ; + data->autofan[2].min_off = (i & 0x80) != 0 ; + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); + data->smooth[1] = (i>>4) & 0x0f ; + data->smooth[2] = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST1); + data->zone[0].hyst = (i>>4) & 0x0f ; + data->zone[1].hyst = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST2); + data->zone[2].hyst = (i>>4) & 0x0f ; + + if ( (data->type == lm85b) || (data->type == lm85c) ) { + data->tach_mode = lm85_read_value(client, + LM85_REG_TACH_MODE ); + data->spinup_ctl = lm85_read_value(client, + LM85_REG_SPINUP_CTL ); + } else if ( (data->type == adt7463) || (data->type == adm1027) ) { + if ( data->type == adt7463 ) { + for (i = 0; i <= 2; ++i) { + data->oppoint[i] = lm85_read_value(client, + ADT7463_REG_OPPOINT(i) ); + } + data->tmin_ctl = lm85_read_value(client, + ADT7463_REG_TMIN_CTL1 ); + data->therm_limit = lm85_read_value(client, + ADT7463_REG_THERM_LIMIT ); + } + for (i = 0; i <= 2; ++i) { + data->temp_offset[i] = lm85_read_value(client, + ADM1027_REG_TEMP_OFFSET(i) ); + } + data->tach_mode = lm85_read_value(client, + ADM1027_REG_CONFIG3 ); + data->fan_ppr = lm85_read_value(client, + ADM1027_REG_FAN_PPR ); + } + + data->last_config = jiffies; + }; /* last_config */ + + data->valid = 1; + + up(&data->update_lock); + + return data; +} + + +static int __init sm_lm85_init(void) +{ + return i2c_add_driver(&lm85_driver); +} + +static void __exit sm_lm85_exit(void) +{ + i2c_del_driver(&lm85_driver); +} + +/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. + * Thanks to Margit Schubert-While for help with + * post 2.7.0 CVS changes. + */ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny , Margit Schubert-While , Justin Thiessen + * Philip Edelbrock + * Stephen Rousset + * Dan Eaton + * Copyright (C) 2004 Jean Delvare + * + * Original port to Linux 2.6 by Jeff Oliver. + * + * The LM87 is a sensor chip made by National Semiconductor. It monitors up + * to 8 voltages (including its own power source), up to three temperatures + * (its own plus up to two external ones) and up to two fans. The default + * configuration is 6 voltages, two temperatures and two fans (see below). + * Voltages are scaled internally with ratios such that the nominal value of + * each voltage correspond to a register value of 192 (which means a + * resolution of about 0.5% of the nominal value). Temperature values are + * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete + * datasheet can be obtained from National's website at: + * http://www.national.com/pf/LM/LM87.html + * + * Some functions share pins, so not all functions are available at the same + * time. Which are depends on the hardware setup. This driver assumes that + * the BIOS configured the chip correctly. In that respect, it differs from + * the original driver (from lm_sensors for Linux 2.4), which would force the + * LM87 to an arbitrary, compile-time chosen mode, regardless of the actual + * chipset wiring. + * For reference, here is the list of exclusive functions: + * - in0+in5 (default) or temp3 + * - fan1 (default) or in6 + * - fan2 (default) or in7 + * - VID lines (default) or IRQ lines (not handled by this driver) + * + * The LM87 additionally features an analog output, supposedly usable to + * control the speed of a fan. All new chips use pulse width modulation + * instead. The LM87 is the only hardware monitoring chipset I know of + * which uses amplitude modulation. Be careful when using this feature. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e. + */ + +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm87); + +/* + * The LM87 registers + */ + +/* nr in 0..5 */ +#define LM87_REG_IN(nr) (0x20 + (nr)) +#define LM87_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define LM87_REG_IN_MIN(nr) (0x2C + (nr) * 2) +/* nr in 0..1 */ +#define LM87_REG_AIN(nr) (0x28 + (nr)) +#define LM87_REG_AIN_MIN(nr) (0x1A + (nr)) +#define LM87_REG_AIN_MAX(nr) (0x3B + (nr)) + +static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 }; +static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B }; +static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; + +#define LM87_REG_TEMP_HW_INT_LOCK 0x13 +#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 +#define LM87_REG_TEMP_HW_INT 0x17 +#define LM87_REG_TEMP_HW_EXT 0x18 + +/* nr in 0..1 */ +#define LM87_REG_FAN(nr) (0x28 + (nr)) +#define LM87_REG_FAN_MIN(nr) (0x3B + (nr)) +#define LM87_REG_AOUT 0x19 + +#define LM87_REG_CONFIG 0x40 +#define LM87_REG_CHANNEL_MODE 0x16 +#define LM87_REG_VID_FAN_DIV 0x47 +#define LM87_REG_VID4 0x49 + +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 + +#define LM87_REG_COMPANY_ID 0x3E +#define LM87_REG_REVISION 0x3F + +/* + * Conversions and various macros + * The LM87 uses signed 8-bit values for temperatures. + */ + +#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ + (val) * 192 >= (scale) * 255 ? 255 : \ + ((val) * 192 + (scale)/2) / (scale)) + +#define TEMP_FROM_REG(reg) ((reg) * 1000) +#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ + (val) >= 126500 ? 127 : \ + (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + +#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ + 1350000 + (reg)*(div) / 2) / ((reg)*(div)) +#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ + (1350000 + (val)*(div) / 2) / ((val)*(div))) + +#define FAN_DIV_FROM_REG(reg) (1 << (reg)) + +/* analog out is 9.80mV/LSB */ +#define AOUT_FROM_REG(reg) (((reg) * 98 + 5) / 10) +#define AOUT_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 2500 ? 255 : \ + ((val) * 10 + 49) / 98) + +/* nr in 0..1 */ +#define CHAN_NO_FAN(nr) (1 << (nr)) +#define CHAN_TEMP3 (1 << 2) +#define CHAN_VCC_5V (1 << 3) +#define CHAN_NO_VID (1 << 8) + +/* + * Functions declaration + */ + +static int lm87_attach_adapter(struct i2c_adapter *adapter); +static int lm87_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm87_init_client(struct i2c_client *client); +static int lm87_detach_client(struct i2c_client *client); +static struct lm87_data *lm87_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm87_driver = { + .owner = THIS_MODULE, + .name = "lm87", + .id = I2C_DRIVERID_LM87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm87_attach_adapter, + .detach_client = lm87_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm87_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 channel; /* register value */ + + u8 in[8]; /* register value */ + u8 in_max[8]; /* register value */ + u8 in_min[8]; /* register value */ + u16 in_scale[8]; + + s8 temp[3]; /* register value */ + s8 temp_high[3]; /* register value */ + s8 temp_low[3]; /* register value */ + s8 temp_crit_int; /* min of two register values */ + s8 temp_crit_ext; /* min of two register values */ + + u8 fan[2]; /* register value */ + u8 fan_min[2]; /* register value */ + u8 fan_div[2]; /* register value, shifted right */ + u8 aout; /* register value */ + + u16 alarms; /* register values, combined */ + u8 vid; /* register values, combined */ + u8 vrm; +}; + +/* + * Sysfs stuff + */ + +static inline int lm87_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +#define show_in(offset) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + data->in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + data->in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + data->in_scale[offset])); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset##_input, NULL); +show_in(0); +show_in(1); +show_in(2); +show_in(3); +show_in(4); +show_in(5); +show_in(6); +show_in(7); + +static void set_in_min(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]); + lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) : + LM87_REG_AIN_MIN(nr-6), data->in_min[nr]); + up(&data->update_lock); +} + +static void set_in_max(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]); + lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) : + LM87_REG_AIN_MAX(nr-6), data->in_max[nr]); + up(&data->update_lock); +} + +#define set_in(offset) \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_in_min(dev, buf, offset); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_in_max(dev, buf, offset); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); +set_in(0); +set_in(1); +set_in(2); +set_in(3); +set_in(4); +set_in(5); +set_in(6); +set_in(7); + +#define show_temp(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ +} \ +static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ +}\ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); +show_temp(1); +show_temp(2); +show_temp(3); + +static void set_temp_low(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_low[nr] = TEMP_TO_REG(val); + lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]); + up(&data->update_lock); +} + +static void set_temp_high(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_high[nr] = TEMP_TO_REG(val); + lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]); + up(&data->update_lock); +} + +#define set_temp(offset) \ +static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_temp_low(dev, buf, offset-1); \ + return count; \ +} \ +static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_temp_high(dev, buf, offset-1); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp##offset##_high, set_temp##offset##_high); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp##offset##_low, set_temp##offset##_low); +set_temp(1); +set_temp(2); +set_temp(3); + +static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); +} + +static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); +} + +static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); +static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); +static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); + +#define show_fan(offset) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ + FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ + FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset##_input, NULL); +show_fan(1); +show_fan(2); + +static void set_fan_min(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, + FAN_DIV_FROM_REG(data->fan_div[nr])); + lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + unsigned long min; + u8 reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + up(&data->update_lock); + return -EINVAL; + } + + reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); + switch (nr) { + case 0: + reg = (reg & 0xCF) | (data->fan_div[0] << 4); + break; + case 1: + reg = (reg & 0x3F) | (data->fan_div[1] << 6); + break; + } + lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); + + data->fan_min[nr] = FAN_TO_REG(min, val); + lm87_write_value(client, LM87_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define set_fan(offset) \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + set_fan_min(dev, buf, offset-1); \ + return count; \ +} \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan##offset##_div, set_fan##offset##_div); +set_fan(1); +set_fan(2); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + lm87_write_value(client, LM87_REG_AOUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* + * Real code + */ + +static int lm87_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm87_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm87_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm87_data)); + + /* The common I2C client data is placed right before the + LM87-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm87_driver; + new_client->flags = 0; + + /* Default to an LM87 if forced */ + if (kind == 0) + kind = lm87; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); + + if (rev < 0x01 || rev > 0x08 + || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) + || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { + dev_dbg(&adapter->dev, + "LM87 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM87 chip */ + lm87_init_client(new_client); + + data->in_scale[0] = 2500; + data->in_scale[1] = 2700; + data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300; + data->in_scale[3] = 5000; + data->in_scale[4] = 12000; + data->in_scale[5] = 2700; + data->in_scale[6] = 1875; + data->in_scale[7] = 1875; + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + + if (data->channel & CHAN_NO_FAN(0)) { + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in6_max); + } else { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } + if (data->channel & CHAN_NO_FAN(1)) { + device_create_file(&new_client->dev, &dev_attr_in7_input); + device_create_file(&new_client->dev, &dev_attr_in7_min); + device_create_file(&new_client->dev, &dev_attr_in7_max); + } else { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } + + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + + if (data->channel & CHAN_TEMP3) { + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + } else { + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + } + + if (!(data->channel & CHAN_NO_VID)) { + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + } + + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void lm87_init_client(struct i2c_client *client) +{ + struct lm87_data *data = i2c_get_clientdata(client); + u8 config; + + data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); + data->vrm = i2c_which_vrm(); + + config = lm87_read_value(client, LM87_REG_CONFIG); + if (!(config & 0x01)) { + int i; + + /* Limits are left uninitialized after power-up */ + for (i = 1; i < 6; i++) { + lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); + } + for (i = 0; i < 2; i++) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); + lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); + } + if (data->channel & CHAN_TEMP3) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); + } else { + lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); + } + } + if ((config & 0x81) != 0x01) { + /* Start monitoring */ + lm87_write_value(client, LM87_REG_CONFIG, + (config & 0xF7) | 0x01); + } +} + +static int lm87_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 struct lm87_data *lm87_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + int i, j; + + dev_dbg(&client->dev, "Updating data.\n"); + + i = (data->channel & CHAN_TEMP3) ? 1 : 0; + j = (data->channel & CHAN_TEMP3) ? 5 : 6; + for (; i < j; i++) { + data->in[i] = lm87_read_value(client, + LM87_REG_IN(i)); + data->in_min[i] = lm87_read_value(client, + LM87_REG_IN_MIN(i)); + data->in_max[i] = lm87_read_value(client, + LM87_REG_IN_MAX(i)); + } + + for (i = 0; i < 2; i++) { + if (data->channel & CHAN_NO_FAN(i)) { + data->in[6+i] = lm87_read_value(client, + LM87_REG_AIN(i)); + data->in_max[6+i] = lm87_read_value(client, + LM87_REG_AIN_MAX(i)); + data->in_min[6+i] = lm87_read_value(client, + LM87_REG_AIN_MIN(i)); + + } else { + data->fan[i] = lm87_read_value(client, + LM87_REG_FAN(i)); + data->fan_min[i] = lm87_read_value(client, + LM87_REG_FAN_MIN(i)); + } + } + + j = (data->channel & CHAN_TEMP3) ? 3 : 2; + for (i = 0 ; i < j; i++) { + data->temp[i] = lm87_read_value(client, + LM87_REG_TEMP[i]); + data->temp_high[i] = lm87_read_value(client, + LM87_REG_TEMP_HIGH[i]); + data->temp_low[i] = lm87_read_value(client, + LM87_REG_TEMP_LOW[i]); + } + + i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); + data->temp_crit_int = min(i, j); + + i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); + data->temp_crit_ext = min(i, j); + + i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->vid = (i & 0x0F) + | (lm87_read_value(client, LM87_REG_VID4) & 0x01) + << 4; + + data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) + | (lm87_read_value(client, LM87_REG_ALARMS2) + << 8); + data->aout = lm87_read_value(client, LM87_REG_AOUT); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm87_init(void) +{ + return i2c_add_driver(&lm87_driver); +} + +static void __exit sensors_lm87_exit(void) +{ + i2c_del_driver(&lm87_driver); +} + +MODULE_AUTHOR("Jean Delvare and others"); +MODULE_DESCRIPTION("LM87 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm87_init); +module_exit(sensors_lm87_exit); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c new file mode 100644 index 00000000000..a67dcadf7cb --- /dev/null +++ b/drivers/hwmon/lm90.c @@ -0,0 +1,655 @@ +/* + * lm90.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2005 Jean Delvare + * + * Based on the lm83 driver. The LM90 is a sensor chip made by National + * Semiconductor. It reports up to two temperatures (its own plus up to + * one external one) with a 0.125 deg resolution (1 deg for local + * temperature) and a 3-4 deg accuracy. Complete datasheet can be + * obtained from National's website at: + * http://www.national.com/pf/LM/LM90.html + * + * This driver also supports the LM89 and LM99, two other sensor chips + * made by National Semiconductor. Both have an increased remote + * temperature measurement accuracy (1 degree), and the LM99 + * additionally shifts remote temperatures (measured and limits) by 16 + * degrees, which allows for higher temperatures measurement. The + * driver doesn't handle it since it can be done easily in user-space. + * Complete datasheets can be obtained from National's website at: + * http://www.national.com/pf/LM/LM89.html + * http://www.national.com/pf/LM/LM99.html + * Note that there is no way to differentiate between both chips. + * + * This driver also supports the LM86, another sensor chip made by + * National Semiconductor. It is exactly similar to the LM90 except it + * has a higher accuracy. + * Complete datasheet can be obtained from National's website at: + * http://www.national.com/pf/LM/LM86.html + * + * This driver also supports the ADM1032, a sensor chip made by Analog + * Devices. That chip is similar to the LM90, with a few differences + * that are not handled by this driver. Complete datasheet can be + * obtained from Analog's website at: + * http://products.analog.com/products/info.asp?product=ADM1032 + * Among others, it has a higher accuracy than the LM90, much like the + * LM86 does. + * + * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor + * chips made by Maxim. These chips are similar to the LM86. Complete + * datasheet can be obtained at Maxim's website at: + * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Note that there is no easy way to differentiate between the three + * variants. The extra address and features of the MAX6659 are not + * supported by this driver. + * + * This driver also supports the ADT7461 chip from Analog Devices but + * only in its "compatability mode". If an ADT7461 chip is found but + * is configured in non-compatible mode (where its temperature + * register values are decoded differently) it is ignored by this + * driver. Complete datasheet can be obtained from Analog's website + * at: + * http://products.analog.com/products/info.asp?product=ADT7461 + * + * Since the LM90 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is fully defined internally and cannot be changed except for + * MAX6659. + * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. + * LM89-1, and LM99-1 have address 0x4d. + * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). + * ADT7461 always has address 0x4c. + */ + +static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); + +/* + * The LM90 registers + */ + +#define LM90_REG_R_MAN_ID 0xFE +#define LM90_REG_R_CHIP_ID 0xFF +#define LM90_REG_R_CONFIG1 0x03 +#define LM90_REG_W_CONFIG1 0x09 +#define LM90_REG_R_CONFIG2 0xBF +#define LM90_REG_W_CONFIG2 0xBF +#define LM90_REG_R_CONVRATE 0x04 +#define LM90_REG_W_CONVRATE 0x0A +#define LM90_REG_R_STATUS 0x02 +#define LM90_REG_R_LOCAL_TEMP 0x00 +#define LM90_REG_R_LOCAL_HIGH 0x05 +#define LM90_REG_W_LOCAL_HIGH 0x0B +#define LM90_REG_R_LOCAL_LOW 0x06 +#define LM90_REG_W_LOCAL_LOW 0x0C +#define LM90_REG_R_LOCAL_CRIT 0x20 +#define LM90_REG_W_LOCAL_CRIT 0x20 +#define LM90_REG_R_REMOTE_TEMPH 0x01 +#define LM90_REG_R_REMOTE_TEMPL 0x10 +#define LM90_REG_R_REMOTE_OFFSH 0x11 +#define LM90_REG_W_REMOTE_OFFSH 0x11 +#define LM90_REG_R_REMOTE_OFFSL 0x12 +#define LM90_REG_W_REMOTE_OFFSL 0x12 +#define LM90_REG_R_REMOTE_HIGHH 0x07 +#define LM90_REG_W_REMOTE_HIGHH 0x0D +#define LM90_REG_R_REMOTE_HIGHL 0x13 +#define LM90_REG_W_REMOTE_HIGHL 0x13 +#define LM90_REG_R_REMOTE_LOWH 0x08 +#define LM90_REG_W_REMOTE_LOWH 0x0E +#define LM90_REG_R_REMOTE_LOWL 0x14 +#define LM90_REG_W_REMOTE_LOWL 0x14 +#define LM90_REG_R_REMOTE_CRIT 0x19 +#define LM90_REG_W_REMOTE_CRIT 0x19 +#define LM90_REG_R_TCRIT_HYST 0x21 +#define LM90_REG_W_TCRIT_HYST 0x21 + +/* + * Conversions and various macros + * For local temperatures and limits, critical limits and the hysteresis + * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. + * For remote temperatures and limits, it uses signed 11-bit values with + * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + */ + +#define TEMP1_FROM_REG(val) ((val) * 1000) +#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) +#define TEMP2_FROM_REG(val) ((val) / 32 * 125) +#define TEMP2_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ + (val) >= 127875 ? 0x7FE0 : \ + (val) < 0 ? ((val) - 62) / 125 * 32 : \ + ((val) + 62) / 125 * 32) +#define HYST_TO_REG(val) ((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \ + ((val) + 500) / 1000) + +/* + * ADT7461 is almost identical to LM90 except that attempts to write + * values that are outside the range 0 < temp < 127 are treated as + * the boundary value. + */ + +#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ + (val) >= 127000 ? 127 : \ + ((val) + 500) / 1000) +#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ + (val) >= 127750 ? 0x7FC0 : \ + ((val) + 125) / 250 * 64) + +/* + * Functions declaration + */ + +static int lm90_attach_adapter(struct i2c_adapter *adapter); +static int lm90_detect(struct i2c_adapter *adapter, int address, + int kind); +static void lm90_init_client(struct i2c_client *client); +static int lm90_detach_client(struct i2c_client *client); +static struct lm90_data *lm90_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm90_driver = { + .owner = THIS_MODULE, + .name = "lm90", + .id = I2C_DRIVERID_LM90, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm90_attach_adapter, + .detach_client = lm90_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm90_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int kind; + + /* registers values */ + s8 temp8[5]; /* 0: local input + 1: local low limit + 2: local high limit + 3: local critical limit + 4: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ + u8 temp_hyst; + u8 alarms; /* bitvector */ +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_LOCAL_LOW, + LM90_REG_W_LOCAL_HIGH, + LM90_REG_W_LOCAL_CRIT, + LM90_REG_W_REMOTE_CRIT, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); + else + data->temp8[nr] = TEMP1_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); +} + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_REMOTE_LOWH, + LM90_REG_W_REMOTE_LOWL, + LM90_REG_W_REMOTE_HIGHH, + LM90_REG_W_REMOTE_HIGHL, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); + else + data->temp11[nr] = TEMP2_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; +} + +static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) + - TEMP1_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + long hyst; + + down(&data->update_lock); + hyst = TEMP1_FROM_REG(data->temp8[3]) - val; + i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, + HYST_TO_REG(hyst)); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 3); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 4); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, + set_temphyst, 3); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm90_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm90_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm90_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm90_data)); + + /* The common I2C client data is placed right before the + LM90-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm90_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + + /* Default to an LM90 if forced */ + if (kind == 0) + kind = lm90; + + if (kind < 0) { /* detection and identification */ + u8 man_id, chip_id, reg_config1, reg_convrate; + + man_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CHIP_ID); + reg_config1 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG1); + reg_convrate = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONVRATE); + + if (man_id == 0x01) { /* National Semiconductor */ + u8 reg_config2; + + reg_config2 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG2); + + if ((reg_config1 & 0x2A) == 0x00 + && (reg_config2 & 0xF8) == 0x00 + && reg_convrate <= 0x09) { + if (address == 0x4C + && (chip_id & 0xF0) == 0x20) { /* LM90 */ + kind = lm90; + } else + if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ + kind = lm99; + } else + if (address == 0x4C + && (chip_id & 0xF0) == 0x10) { /* LM86 */ + kind = lm86; + } + } + } else + if (man_id == 0x41) { /* Analog Devices */ + if (address == 0x4C + && (chip_id & 0xF0) == 0x40 /* ADM1032 */ + && (reg_config1 & 0x3F) == 0x00 + && reg_convrate <= 0x0A) { + kind = adm1032; + } else + if (address == 0x4c + && chip_id == 0x51 /* ADT7461 */ + && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ + && reg_convrate <= 0x0A) { + kind = adt7461; + } + } else + if (man_id == 0x4D) { /* Maxim */ + /* + * The Maxim variants do NOT have a chip_id register. + * Reading from that address will return the last read + * value, which in our case is those of the man_id + * register. Likewise, the config1 register seems to + * lack a low nibble, so the value will be those of the + * previous read, so in our case those of the man_id + * register. + */ + if (chip_id == man_id + && (reg_config1 & 0x1F) == (man_id & 0x0F) + && reg_convrate <= 0x09) { + kind = max6657; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == lm90) { + name = "lm90"; + } else if (kind == adm1032) { + name = "adm1032"; + } else if (kind == lm99) { + name = "lm99"; + } else if (kind == lm86) { + name = "lm86"; + } else if (kind == max6657) { + name = "max6657"; + } else if (kind == adt7461) { + name = "adt7461"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + data->kind = kind; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM90 chip */ + lm90_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_hyst.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void lm90_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); + if (config & 0x40) + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, + config & 0xBF); /* run */ +} + +static int lm90_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 struct lm90_data *lm90_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + u8 oldh, newh; + + dev_dbg(&client->dev, "Updating lm90 data.\n"); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_LOW); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_HIGH); + data->temp8[3] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_CRIT); + data->temp8[4] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_CRIT); + data->temp_hyst = i2c_smbus_read_byte_data(client, + LM90_REG_R_TCRIT_HYST); + + /* + * There is a trick here. We have to read two registers to + * have the remote sensor temperature, but we have to beware + * a conversion could occur inbetween the readings. The + * datasheet says we should either use the one-shot + * conversion register, which we don't want to do (disables + * hardware monitoring) or monitor the busy bit, which is + * impossible (we can't read the values and monitor that bit + * at the exact same time). So the solution used here is to + * read the high byte once, then the low byte, then the high + * byte again. If the new high byte matches the old one, + * then we have a valid reading. Else we have to read the low + * byte again, and now we believe we have a correct reading. + */ + oldh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); + newh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + if (newh != oldh) { + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); +#ifdef DEBUG + oldh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + /* oldh is actually newer */ + if (newh != oldh) + dev_warn(&client->dev, "Remote temperature may be " + "wrong.\n"); +#endif + } + data->temp11[0] |= (newh << 8); + + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWL); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_HIGHH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_HIGHL); + data->alarms = i2c_smbus_read_byte_data(client, + LM90_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm90_init(void) +{ + return i2c_add_driver(&lm90_driver); +} + +static void __exit sensors_lm90_exit(void) +{ + i2c_del_driver(&lm90_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM90/ADM1032 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm90_init); +module_exit(sensors_lm90_exit); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c new file mode 100644 index 00000000000..215c8e40ffd --- /dev/null +++ b/drivers/hwmon/lm92.c @@ -0,0 +1,429 @@ +/* + * lm92 - Hardware monitoring driver + * Copyright (C) 2005 Jean Delvare + * + * Based on the lm90 driver, with some ideas taken from the lm_sensors + * lm92 driver as well. + * + * The LM92 is a sensor chip made by National Semiconductor. It reports + * its own temperature with a 0.0625 deg resolution and a 0.33 deg + * accuracy. Complete datasheet can be obtained from National's website + * at: + * http://www.national.com/pf/LM/LM92.html + * + * This driver also supports the MAX6635 sensor chip made by Maxim. + * This chip is compatible with the LM92, but has a lesser accuracy + * (1.0 deg). Complete datasheet can be obtained from Maxim's website + * at: + * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 + * + * Since the LM92 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * Support could easily be added for the National Semiconductor LM76 + * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible + * with the LM92. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + + +/* The LM92 and MAX6635 have 2 two-state pins for address selection, + resulting in 4 possible addresses. */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm92); + +/* The LM92 registers */ +#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ +#define LM92_REG_TEMP 0x00 /* 16-bit, RO */ +#define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ +#define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ +#define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ +#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ +#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ + +/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, + left-justified in 16-bit registers. No rounding is done, with such + a resolution it's just not worth it. Note that the MAX6635 doesn't + make use of the 4 lower bits for limits (i.e. effective resolution + for limits is 1 degree Celsius). */ +static inline int TEMP_FROM_REG(s16 reg) +{ + return reg / 8 * 625 / 10; +} + +static inline s16 TEMP_TO_REG(int val) +{ + if (val <= -60000) + return -60000 * 10 / 625 * 8; + if (val >= 160000) + return 160000 * 10 / 625 * 8; + return val * 10 / 625 * 8; +} + +/* Alarm flags are stored in the 3 LSB of the temperature register */ +static inline u8 ALARMS_FROM_REG(s16 reg) +{ + return reg & 0x0007; +} + +/* Driver data (common to all clients) */ +static struct i2c_driver lm92_driver; + +/* Client data (each client gets its own) */ +struct lm92_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; +}; + + +/* + * Sysfs attributes and callback functions + */ + +static struct lm92_data *lm92_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + dev_dbg(&client->dev, "Updating lm92 data\n"); + data->temp1_input = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP)); + data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HYST)); + data->temp1_crit = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_CRIT)); + data->temp1_min = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_LOW)); + data->temp1_max = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HIGH)); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm92_data *data = lm92_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show_temp(temp1_input); +show_temp(temp1_crit); +show_temp(temp1_min); +show_temp(temp1_max); + +#define set_temp(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm92_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ + up(&data->update_lock); \ + return count; \ +} +set_temp(temp1_crit, LM92_REG_TEMP_CRIT); +set_temp(temp1_min, LM92_REG_TEMP_LOW); +set_temp(temp1_max, LM92_REG_TEMP_HIGH); + +static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) + - TEMP_FROM_REG(data->temp1_hyst)); +} +static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) + - TEMP_FROM_REG(data->temp1_hyst)); +} +static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) + + TEMP_FROM_REG(data->temp1_hyst)); +} + +static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; + i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, + swab16(TEMP_TO_REG(data->temp1_hyst))); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, + set_temp1_crit); +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, + set_temp1_crit_hyst); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, + set_temp1_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, + set_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +/* + * Detection and registration + */ + +static void lm92_init_client(struct i2c_client *client) +{ + u8 config; + + /* Start the conversions if needed */ + config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); + if (config & 0x01) + i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, + config & 0xFE); +} + +/* The MAX6635 has no identification register, so we have to use tricks + to identify it reliably. This is somewhat slow. + Note that we do NOT rely on the 2 MSB of the configuration register + always reading 0, as suggested by the datasheet, because it was once + reported not to be true. */ +static int max6635_check(struct i2c_client *client) +{ + u16 temp_low, temp_high, temp_hyst, temp_crit; + u8 conf; + int i; + + /* No manufacturer ID register, so a read from this address will + always return the last read value. */ + temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW); + if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low) + return 0; + temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH); + if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high) + return 0; + + /* Limits are stored as integer values (signed, 9-bit). */ + if ((temp_low & 0x7f00) || (temp_high & 0x7f00)) + return 0; + temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST); + temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT); + if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) + return 0; + + /* Registers addresses were found to cycle over 16-byte boundaries. + We don't test all registers with all offsets so as to save some + reads and time, but this should still be sufficient to dismiss + non-MAX6635 chips. */ + conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); + for (i=16; i<96; i*=2) { + if (temp_hyst != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HYST + i - 16) + || temp_crit != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_CRIT + i) + || temp_low != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_LOW + i + 16) + || temp_high != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HIGH + i + 32) + || conf != i2c_smbus_read_byte_data(client, + LM92_REG_CONFIG + i)) + return 0; + } + + return 1; +} + +/* The following function does more than just detection. If detection + succeeds, it also registers the new chip. */ +static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm92_data *data; + int err = 0; + char *name; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm92_data)); + + /* Fill in enough client fields so that we can read from the chip, + which is required for identication */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm92_driver; + new_client->flags = 0; + + /* A negative kind means that the driver was loaded with no force + parameter (default), so we must identify the chip. */ + if (kind < 0) { + u8 config = i2c_smbus_read_byte_data(new_client, + LM92_REG_CONFIG); + u16 man_id = i2c_smbus_read_word_data(new_client, + LM92_REG_MAN_ID); + + if ((config & 0xe0) == 0x00 + && man_id == 0x0180) { + pr_info("lm92: Found National Semiconductor LM92 chip\n"); + kind = lm92; + } else + if (max6635_check(new_client)) { + pr_info("lm92: Found Maxim MAX6635 chip\n"); + kind = lm92; /* No separate prefix */ + } + else + goto exit_free; + } else + if (kind == 0) /* Default to an LM92 if forced */ + kind = lm92; + + /* Give it the proper name */ + if (kind == lm92) { + name = "lm92"; + } else { /* Supposedly cannot happen */ + dev_dbg(&new_client->dev, "Kind out of range?\n"); + goto exit_free; + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the i2c subsystem a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the chipset */ + lm92_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm92_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm92_detect); +} + +static int lm92_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + + +/* + * Module and driver stuff + */ + +static struct i2c_driver lm92_driver = { + .owner = THIS_MODULE, + .name = "lm92", + .id = I2C_DRIVERID_LM92, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm92_attach_adapter, + .detach_client = lm92_detach_client, +}; + +static int __init sensors_lm92_init(void) +{ + return i2c_add_driver(&lm92_driver); +} + +static void __exit sensors_lm92_exit(void) +{ + i2c_del_driver(&lm92_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM92/MAX6635 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm92_init); +module_exit(sensors_lm92_exit); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c new file mode 100644 index 00000000000..bf553dcd97d --- /dev/null +++ b/drivers/hwmon/max1619.c @@ -0,0 +1,372 @@ +/* + * max1619.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2004 Alexey Fisher + * Jean Delvare + * + * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. + * It reports up to two temperatures (its own plus up to + * one external one). Complete datasheet can be + * obtained from Maxim's website at: + * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include + + +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(max1619); + +/* + * The MAX1619 registers + */ + +#define MAX1619_REG_R_MAN_ID 0xFE +#define MAX1619_REG_R_CHIP_ID 0xFF +#define MAX1619_REG_R_CONFIG 0x03 +#define MAX1619_REG_W_CONFIG 0x09 +#define MAX1619_REG_R_CONVRATE 0x04 +#define MAX1619_REG_W_CONVRATE 0x0A +#define MAX1619_REG_R_STATUS 0x02 +#define MAX1619_REG_R_LOCAL_TEMP 0x00 +#define MAX1619_REG_R_REMOTE_TEMP 0x01 +#define MAX1619_REG_R_REMOTE_HIGH 0x07 +#define MAX1619_REG_W_REMOTE_HIGH 0x0D +#define MAX1619_REG_R_REMOTE_LOW 0x08 +#define MAX1619_REG_W_REMOTE_LOW 0x0E +#define MAX1619_REG_R_REMOTE_CRIT 0x10 +#define MAX1619_REG_W_REMOTE_CRIT 0x12 +#define MAX1619_REG_R_TCRIT_HYST 0x11 +#define MAX1619_REG_W_TCRIT_HYST 0x13 + +/* + * Conversions and various macros + */ + +#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) +#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000) + +/* + * Functions declaration + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter); +static int max1619_detect(struct i2c_adapter *adapter, int address, + int kind); +static void max1619_init_client(struct i2c_client *client); +static int max1619_detach_client(struct i2c_client *client); +static struct max1619_data *max1619_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver max1619_driver = { + .owner = THIS_MODULE, + .name = "max1619", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max1619_attach_adapter, + .detach_client = max1619_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct max1619_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 temp_input1; /* local */ + u8 temp_input2, temp_low2, temp_high2; /* remote */ + u8 temp_crit2; + u8 temp_hyst2; + u8 alarms; +}; + +/* + * Sysfs stuff + */ + +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct max1619_data *data = max1619_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show_temp(temp_input1); +show_temp(temp_input2); +show_temp(temp_low2); +show_temp(temp_high2); +show_temp(temp_crit2); +show_temp(temp_hyst2); + +#define set_temp2(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct max1619_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); +set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); +set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); +set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct max1619_data *data = max1619_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, + set_temp_low2); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, + set_temp_high2); +static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, + set_temp_crit2); +static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, + set_temp_hyst2); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, max1619_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct max1619_data *data; + int err = 0; + const char *name = ""; + u8 reg_config=0, reg_convrate=0, reg_status=0; + u8 man_id, chip_id; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct max1619_data)); + + /* The common I2C client data is placed right before the + MAX1619-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &max1619_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + reg_config = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONFIG); + reg_convrate = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONVRATE); + reg_status = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_STATUS); + if ((reg_config & 0x03) != 0x00 + || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) { + dev_dbg(&adapter->dev, + "MAX1619 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + + man_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CHIP_ID); + + if ((man_id == 0x4D) && (chip_id == 0x04)){ + kind = max1619; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + + + if (kind == max1619){ + name = "max1619"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the MAX1619 chip */ + max1619_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void max1619_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (config & 0x40) + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, + config & 0xBF); /* run */ +} + +static int max1619_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 struct max1619_data *max1619_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Updating max1619 data.\n"); + data->temp_input1 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_LOCAL_TEMP); + data->temp_input2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TEMP); + data->temp_high2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_HIGH); + data->temp_low2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_LOW); + data->temp_crit2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_CRIT); + data->temp_hyst2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_TCRIT_HYST); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_max1619_init(void) +{ + return i2c_add_driver(&max1619_driver); +} + +static void __exit sensors_max1619_exit(void) +{ + i2c_del_driver(&max1619_driver); +} + +MODULE_AUTHOR("Alexey Fisher and" + "Jean Delvare "); +MODULE_DESCRIPTION("MAX1619 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_max1619_init); +module_exit(sensors_max1619_exit); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c new file mode 100644 index 00000000000..876c68f3af3 --- /dev/null +++ b/drivers/hwmon/pc87360.c @@ -0,0 +1,1348 @@ +/* + * pc87360.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * Copyright (C) 2004 Jean Delvare + * + * Copied from smsc47m1.c: + * Copyright (C) 2002 Mark D. Studebaker + * + * 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. + * + * Supports the following chips: + * + * Chip #vin #fan #pwm #temp devid + * PC87360 - 2 2 - 0xE1 + * PC87363 - 2 2 - 0xE8 + * PC87364 - 3 3 - 0xE4 + * PC87365 11 3 3 2 0xE5 + * PC87366 11 3 3 3-4 0xE9 + * + * This driver assumes that no more than one chip is present, and one of + * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{ NULL }}; +static u8 devid; +static unsigned int extra_isa[3]; +static u8 confreg[4]; + +enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .forces = forces, +}; + +static int init = 1; +module_param(init, int, 0); +MODULE_PARM_DESC(init, + "Chip initialization level:\n" + " 0: None\n" + "*1: Forcibly enable internal voltage and temperature channels, except in9\n" + " 2: Forcibly enable all voltage and temperature channels, except in9\n" + " 3: Forcibly enable all voltage and temperature channels, including in9"); + +/* + * Super-I/O registers and operations + */ + +#define DEV 0x07 /* Register: Logical device select */ +#define DEVID 0x20 /* Register: Device ID */ +#define ACT 0x30 /* Register: Device activation */ +#define BASE 0x60 /* Register: Base address */ + +#define FSCM 0x09 /* Logical device: fans */ +#define VLM 0x0d /* Logical device: voltages */ +#define TMS 0x0e /* Logical device: temperatures */ +static const u8 logdev[3] = { FSCM, VLM, TMS }; + +#define LD_FAN 0 +#define LD_IN 1 +#define LD_TEMP 2 + +static inline void superio_outb(int sioaddr, int reg, int val) +{ + outb(reg, sioaddr); + outb(val, sioaddr+1); +} + +static inline int superio_inb(int sioaddr, int reg) +{ + outb(reg, sioaddr); + return inb(sioaddr+1); +} + +static inline void superio_exit(int sioaddr) +{ + outb(0x02, sioaddr); + outb(0x02, sioaddr+1); +} + +/* + * Logical devices + */ + +#define PC87360_EXTENT 0x10 +#define PC87365_REG_BANK 0x09 +#define NO_BANK 0xff + +/* + * Fan registers and conversions + */ + +/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ +#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) +#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) +#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) +#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) +#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) + +#define FAN_FROM_REG(val,div) ((val) == 0 ? 0: \ + 480000 / ((val)*(div))) +#define FAN_TO_REG(val,div) ((val) <= 100 ? 0 : \ + 480000 / ((val)*(div))) +#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) +#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) + +#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) +#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) +#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) + +#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) +static inline u8 PWM_TO_REG(int val, int inv) +{ + if (inv) + val = 255 - val; + if (val < 0) + return 0; + if (val > 255) + return 255; + return val; +} + +/* + * Voltage registers and conversions + */ + +#define PC87365_REG_IN_CONVRATE 0x07 +#define PC87365_REG_IN_CONFIG 0x08 +#define PC87365_REG_IN 0x0B +#define PC87365_REG_IN_MIN 0x0D +#define PC87365_REG_IN_MAX 0x0C +#define PC87365_REG_IN_STATUS 0x0A +#define PC87365_REG_IN_ALARMS1 0x00 +#define PC87365_REG_IN_ALARMS2 0x01 +#define PC87365_REG_VID 0x06 + +#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) +#define IN_TO_REG(val,ref) ((val) < 0 ? 0 : \ + (val)*256 >= (ref)*255 ? 255: \ + ((val) * 256 + (ref)/2) / (ref)) + +/* + * Temperature registers and conversions + */ + +#define PC87365_REG_TEMP_CONFIG 0x08 +#define PC87365_REG_TEMP 0x0B +#define PC87365_REG_TEMP_MIN 0x0D +#define PC87365_REG_TEMP_MAX 0x0C +#define PC87365_REG_TEMP_CRIT 0x0E +#define PC87365_REG_TEMP_STATUS 0x0A +#define PC87365_REG_TEMP_ALARMS 0x00 + +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : \ + (val) > 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) + +/* + * Client data (each client gets its own) + */ + +struct pc87360_data { + struct i2c_client client; + struct semaphore lock; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + int address[3]; + + u8 fannr, innr, tempnr; + + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 fan_status[3]; /* Register value */ + u8 pwm[3]; /* Register value */ + u16 fan_conf; /* Configuration register values, combined */ + + u16 in_vref; /* 1 mV/bit */ + u8 in[14]; /* Register value */ + u8 in_min[14]; /* Register value */ + u8 in_max[14]; /* Register value */ + u8 in_crit[3]; /* Register value */ + u8 in_status[14]; /* Register value */ + u16 in_alarms; /* Register values, combined, masked */ + u8 vid_conf; /* Configuration register value */ + u8 vrm; + u8 vid; /* Register value */ + + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_crit[3]; /* Register value */ + u8 temp_status[3]; /* Register value */ + u8 temp_alarms; /* Register value, masked */ +}; + +/* + * Functions declaration + */ + +static int pc87360_attach_adapter(struct i2c_adapter *adapter); +static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind); +static int pc87360_detach_client(struct i2c_client *client); + +static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg); +static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value); +static void pc87360_init_client(struct i2c_client *client, int use_thermistors); +static struct pc87360_data *pc87360_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver pc87360_driver = { + .owner = THIS_MODULE, + .name = "pc87360", + .flags = I2C_DF_NOTIFY, + .attach_adapter = pc87360_attach_adapter, + .detach_client = pc87360_detach_client, +}; + +/* + * Sysfs stuff + */ + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + long fan_min = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr])); + + /* If it wouldn't fit, change clock divisor */ + while (fan_min > 255 + && (data->fan_status[nr] & 0x60) != 0x60) { + fan_min >>= 1; + data->fan[nr] >>= 1; + data->fan_status[nr] += 0x20; + } + data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr), + data->fan_min[nr]); + + /* Write new divider, preserve alarm bits */ + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr), + data->fan_status[nr] & 0xF9); + up(&data->update_lock); + + return count; +} + +#define show_and_set_fan(offset) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \ + FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \ + FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + FAN_DIV_FROM_REG(data->fan_status[offset-1])); \ +} \ +static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \ +} \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset##_input, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \ + show_fan##offset##_status, NULL); +show_and_set_fan(1) +show_and_set_fan(2) +show_and_set_fan(3) + +#define show_and_set_pwm(offset) \ +static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + PWM_FROM_REG(data->pwm[offset-1], \ + FAN_CONFIG_INVERT(data->fan_conf, \ + offset-1))); \ +} \ +static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->pwm[offset-1] = PWM_TO_REG(val, \ + FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \ + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \ + data->pwm[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \ + show_pwm##offset, set_pwm##offset); +show_and_set_pwm(1) +show_and_set_pwm(2) +show_and_set_pwm(3) + +#define show_and_set_in(offset) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", data->in_status[offset]); \ +} \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \ + data->in_min[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset] = IN_TO_REG(val, \ + data->in_vref); \ + pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \ + data->in_max[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset##_input, NULL); \ +static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in##offset##_max, set_in##offset##_max); \ +static DEVICE_ATTR(in##offset##_status, S_IRUGO, \ + show_in##offset##_status, NULL); +show_and_set_in(0) +show_and_set_in(1) +show_and_set_in(2) +show_and_set_in(3) +show_and_set_in(4) +show_and_set_in(5) +show_and_set_in(6) +show_and_set_in(7) +show_and_set_in(8) +show_and_set_in(9) +show_and_set_in(10) + +#define show_and_set_therm(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", data->in_status[offset+7]); \ +} \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \ + data->in_min[offset+7]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \ + data->in_max[offset+7]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \ + data->in_crit[offset-4]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ + show_temp##offset##_crit, set_temp##offset##_crit); \ +static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ + show_temp##offset##_status, NULL); +show_and_set_therm(4) +show_and_set_therm(5) +show_and_set_therm(6) + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->in_alarms); +} +static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); + +#define show_and_set_temp(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ +}\ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \ +}\ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", data->temp_status[offset-1]); \ +}\ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_min[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \ + data->temp_min[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_max[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \ + data->temp_max[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_crit[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \ + data->temp_crit[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ + show_temp##offset##_crit, set_temp##offset##_crit); \ +static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ + show_temp##offset##_status, NULL); +show_and_set_temp(1) +show_and_set_temp(2) +show_and_set_temp(3) + +static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->temp_alarms); +} +static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); + +/* + * Device detection, registration and update + */ + +static int pc87360_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pc87360_detect); +} + +static int pc87360_find(int sioaddr, u8 *devid, int *address) +{ + u16 val; + int i; + int nrdev; /* logical device count */ + + /* No superio_enter */ + + /* Identify device */ + val = superio_inb(sioaddr, DEVID); + switch (val) { + case 0xE1: /* PC87360 */ + case 0xE8: /* PC87363 */ + case 0xE4: /* PC87364 */ + nrdev = 1; + break; + case 0xE5: /* PC87365 */ + case 0xE9: /* PC87366 */ + nrdev = 3; + break; + default: + superio_exit(sioaddr); + return -ENODEV; + } + /* Remember the device id */ + *devid = val; + + for (i = 0; i < nrdev; i++) { + /* select logical device */ + superio_outb(sioaddr, DEV, logdev[i]); + + val = superio_inb(sioaddr, ACT); + if (!(val & 0x01)) { + printk(KERN_INFO "pc87360: Device 0x%02x not " + "activated\n", logdev[i]); + continue; + } + + val = (superio_inb(sioaddr, BASE) << 8) + | superio_inb(sioaddr, BASE + 1); + if (!val) { + printk(KERN_INFO "pc87360: Base address not set for " + "device 0x%02x\n", logdev[i]); + continue; + } + + address[i] = val; + + if (i==0) { /* Fans */ + confreg[0] = superio_inb(sioaddr, 0xF0); + confreg[1] = superio_inb(sioaddr, 0xF1); + +#ifdef DEBUG + printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " + "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, + (confreg[0]>>3)&1, (confreg[0]>>4)&1); + printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " + "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, + (confreg[0]>>6)&1, (confreg[0]>>7)&1); + printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " + "ctrl=%d inv=%d\n", confreg[1]&1, + (confreg[1]>>1)&1, (confreg[1]>>2)&1); +#endif + } else if (i==1) { /* Voltages */ + /* Are we using thermistors? */ + if (*devid == 0xE9) { /* PC87366 */ + /* These registers are not logical-device + specific, just that we won't need them if + we don't use the VLM device */ + confreg[2] = superio_inb(sioaddr, 0x2B); + confreg[3] = superio_inb(sioaddr, 0x25); + + if (confreg[2] & 0x40) { + printk(KERN_INFO "pc87360: Using " + "thermistors for temperature " + "monitoring\n"); + } + if (confreg[3] & 0xE0) { + printk(KERN_INFO "pc87360: VID " + "inputs routed (mode %u)\n", + confreg[3] >> 5); + } + } + } + } + + superio_exit(sioaddr); + return 0; +} + +/* We don't really care about the address. + Read from extra_isa instead. */ +int pc87360_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct pc87360_data *data; + int err = 0; + const char *name = "pc87360"; + int use_thermistors = 0; + + if (!i2c_is_isa_adapter(adapter)) + return -ENODEV; + + if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + return -ENOMEM; + memset(data, 0x00, sizeof(struct pc87360_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &pc87360_driver; + new_client->flags = 0; + + data->fannr = 2; + data->innr = 0; + data->tempnr = 0; + + switch (devid) { + case 0xe8: + name = "pc87363"; + break; + case 0xe4: + name = "pc87364"; + data->fannr = 3; + break; + case 0xe5: + name = "pc87365"; + data->fannr = extra_isa[0] ? 3 : 0; + data->innr = extra_isa[1] ? 11 : 0; + data->tempnr = extra_isa[2] ? 2 : 0; + break; + case 0xe9: + name = "pc87366"; + data->fannr = extra_isa[0] ? 3 : 0; + data->innr = extra_isa[1] ? 14 : 0; + data->tempnr = extra_isa[2] ? 3 : 0; + break; + } + + strcpy(new_client->name, name); + data->valid = 0; + init_MUTEX(&data->update_lock); + + for (i = 0; i < 3; i++) { + if (((data->address[i] = extra_isa[i])) + && !request_region(extra_isa[i], PC87360_EXTENT, + pc87360_driver.name)) { + dev_err(&new_client->dev, "Region 0x%x-0x%x already " + "in use!\n", extra_isa[i], + extra_isa[i]+PC87360_EXTENT-1); + for (i--; i >= 0; i--) + release_region(extra_isa[i], PC87360_EXTENT); + err = -EBUSY; + goto ERROR1; + } + } + + /* Retrieve the fans configuration from Super-I/O space */ + if (data->fannr) + data->fan_conf = confreg[0] | (confreg[1] << 8); + + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* Use the correct reference voltage + Unless both the VLM and the TMS logical devices agree to + use an external Vref, the internal one is used. */ + if (data->innr) { + i = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG); + if (data->tempnr) { + i &= pc87360_read_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG); + } + data->in_vref = (i&0x02) ? 3025 : 2966; + dev_dbg(&new_client->dev, "Using %s reference voltage\n", + (i&0x02) ? "external" : "internal"); + + data->vid_conf = confreg[3]; + data->vrm = 90; + } + + /* Fan clock dividers may be needed before any data is read */ + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) + data->fan_status[i] = pc87360_read_value(data, + LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(i)); + } + + if (init > 0) { + if (devid == 0xe9 && data->address[1]) /* PC87366 */ + use_thermistors = confreg[2] & 0x40; + + pc87360_init_client(new_client, use_thermistors); + } + + /* Register sysfs hooks */ + if (data->innr) { + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in7_input); + device_create_file(&new_client->dev, &dev_attr_in8_input); + device_create_file(&new_client->dev, &dev_attr_in9_input); + device_create_file(&new_client->dev, &dev_attr_in10_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in7_min); + device_create_file(&new_client->dev, &dev_attr_in8_min); + device_create_file(&new_client->dev, &dev_attr_in9_min); + device_create_file(&new_client->dev, &dev_attr_in10_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_max); + device_create_file(&new_client->dev, &dev_attr_in7_max); + device_create_file(&new_client->dev, &dev_attr_in8_max); + device_create_file(&new_client->dev, &dev_attr_in9_max); + device_create_file(&new_client->dev, &dev_attr_in10_max); + device_create_file(&new_client->dev, &dev_attr_in0_status); + device_create_file(&new_client->dev, &dev_attr_in1_status); + device_create_file(&new_client->dev, &dev_attr_in2_status); + device_create_file(&new_client->dev, &dev_attr_in3_status); + device_create_file(&new_client->dev, &dev_attr_in4_status); + device_create_file(&new_client->dev, &dev_attr_in5_status); + device_create_file(&new_client->dev, &dev_attr_in6_status); + device_create_file(&new_client->dev, &dev_attr_in7_status); + device_create_file(&new_client->dev, &dev_attr_in8_status); + device_create_file(&new_client->dev, &dev_attr_in9_status); + device_create_file(&new_client->dev, &dev_attr_in10_status); + + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_alarms_in); + } + + if (data->tempnr) { + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_status); + device_create_file(&new_client->dev, &dev_attr_temp2_status); + + device_create_file(&new_client->dev, &dev_attr_alarms_temp); + } + if (data->tempnr == 3) { + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_status); + } + if (data->innr == 14) { + device_create_file(&new_client->dev, &dev_attr_temp4_input); + device_create_file(&new_client->dev, &dev_attr_temp5_input); + device_create_file(&new_client->dev, &dev_attr_temp6_input); + device_create_file(&new_client->dev, &dev_attr_temp4_min); + device_create_file(&new_client->dev, &dev_attr_temp5_min); + device_create_file(&new_client->dev, &dev_attr_temp6_min); + device_create_file(&new_client->dev, &dev_attr_temp4_max); + device_create_file(&new_client->dev, &dev_attr_temp5_max); + device_create_file(&new_client->dev, &dev_attr_temp6_max); + device_create_file(&new_client->dev, &dev_attr_temp4_crit); + device_create_file(&new_client->dev, &dev_attr_temp5_crit); + device_create_file(&new_client->dev, &dev_attr_temp6_crit); + device_create_file(&new_client->dev, &dev_attr_temp4_status); + device_create_file(&new_client->dev, &dev_attr_temp5_status); + device_create_file(&new_client->dev, &dev_attr_temp6_status); + } + + if (data->fannr) { + if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { + device_create_file(&new_client->dev, + &dev_attr_fan1_input); + device_create_file(&new_client->dev, + &dev_attr_fan1_min); + device_create_file(&new_client->dev, + &dev_attr_fan1_div); + device_create_file(&new_client->dev, + &dev_attr_fan1_status); + } + + if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { + device_create_file(&new_client->dev, + &dev_attr_fan2_input); + device_create_file(&new_client->dev, + &dev_attr_fan2_min); + device_create_file(&new_client->dev, + &dev_attr_fan2_div); + device_create_file(&new_client->dev, + &dev_attr_fan2_status); + } + + if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) + device_create_file(&new_client->dev, &dev_attr_pwm1); + if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) + device_create_file(&new_client->dev, &dev_attr_pwm2); + } + if (data->fannr == 3) { + if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { + device_create_file(&new_client->dev, + &dev_attr_fan3_input); + device_create_file(&new_client->dev, + &dev_attr_fan3_min); + device_create_file(&new_client->dev, + &dev_attr_fan3_div); + device_create_file(&new_client->dev, + &dev_attr_fan3_status); + } + + if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) + device_create_file(&new_client->dev, &dev_attr_pwm3); + } + + return 0; + +ERROR2: + for (i = 0; i < 3; i++) { + if (data->address[i]) { + release_region(data->address[i], PC87360_EXTENT); + } + } +ERROR1: + kfree(data); + return err; +} + +static int pc87360_detach_client(struct i2c_client *client) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + int i; + + if ((i = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return i; + } + + for (i = 0; i < 3; i++) { + if (data->address[i]) { + release_region(data->address[i], PC87360_EXTENT); + } + } + kfree(data); + + return 0; +} + +/* ldi is the logical device index + bank is for voltages and temperatures only */ +static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg) +{ + int res; + + down(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + res = inb_p(data->address[ldi] + reg); + up(&(data->lock)); + + return res; +} + +static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value) +{ + down(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + outb_p(value, data->address[ldi] + reg); + up(&(data->lock)); +} + +static void pc87360_init_client(struct i2c_client *client, int use_thermistors) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + int i, nr; + const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; + const u8 init_temp[3] = { 2, 2, 1 }; + u8 reg; + + if (init >= 2 && data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE); + dev_info(&client->dev, "VLM conversion set to" + "1s period, 160us delay\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE, + (reg & 0xC0) | 0x11); + } + + nr = data->innr < 11 ? data->innr : 11; + for (i=0; i= init_in[i]) { + /* Forcibly enable voltage channel */ + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling in%d\n", i); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + (reg & 0x68) | 0x87); + } + } + } + + /* We can't blindly trust the Super-I/O space configuration bit, + most BIOS won't set it properly */ + for (i=11; iinnr; i++) { + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS); + use_thermistors = use_thermistors || (reg & 0x01); + } + + i = use_thermistors ? 2 : 0; + for (; itempnr; i++) { + if (init >= init_temp[i]) { + /* Forcibly enable temperature channel */ + reg = pc87360_read_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling temp%d\n", i+1); + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + 0xCF); + } + } + } + + if (use_thermistors) { + for (i=11; iinnr; i++) { + if (init >= init_in[i]) { + /* The pin may already be used by thermal + diodes */ + reg = pc87360_read_value(data, LD_TEMP, + (i-11)/2, PC87365_REG_TEMP_STATUS); + if (reg & 0x01) { + dev_dbg(&client->dev, "Skipping " + "temp%d, pin already in use " + "by temp%d\n", i-7, (i-11)/2); + continue; + } + + /* Forcibly enable thermistor channel */ + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling temp%d\n", i-7); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS, + (reg & 0x60) | 0x8F); + } + } + } + } + + if (data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG); + if (reg & 0x01) { + dev_dbg(&client->dev, "Forcibly " + "enabling monitoring (VLM)\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG, + reg & 0xFE); + } + } + + if (data->tempnr) { + reg = pc87360_read_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG); + if (reg & 0x01) { + dev_dbg(&client->dev, "Forcibly enabling " + "monitoring (TMS)\n"); + pc87360_write_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG, + reg & 0xFE); + } + + if (init >= 2) { + /* Chip config as documented by National Semi. */ + pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); + /* We voluntarily omit the bank here, in case the + sequence itself matters. It shouldn't be a problem, + since nobody else is supposed to access the + device at that point. */ + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); + } + } +} + +static void pc87360_autodiv(struct i2c_client *client, int nr) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + u8 old_min = data->fan_min[nr]; + + /* Increase clock divider if needed and possible */ + if ((data->fan_status[nr] & 0x04) /* overflow flag */ + || (data->fan[nr] >= 224)) { /* next to overflow */ + if ((data->fan_status[nr] & 0x60) != 0x60) { + data->fan_status[nr] += 0x20; + data->fan_min[nr] >>= 1; + data->fan[nr] >>= 1; + dev_dbg(&client->dev, "Increasing " + "clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); + } + } else { + /* Decrease clock divider if possible */ + while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ + && data->fan[nr] < 85 /* bad accuracy */ + && (data->fan_status[nr] & 0x60) != 0x00) { + data->fan_status[nr] -= 0x20; + data->fan_min[nr] <<= 1; + data->fan[nr] <<= 1; + dev_dbg(&client->dev, "Decreasing " + "clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), + nr+1); + } + } + + /* Write new fan min if it changed */ + if (old_min != data->fan_min[nr]) { + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(nr), + data->fan_min[nr]); + } +} + +static struct pc87360_data *pc87360_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + u8 i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Data update\n"); + + /* Fans */ + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { + data->fan_status[i] = + pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN_STATUS(i)); + data->fan[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN(i)); + data->fan_min[i] = pc87360_read_value(data, + LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(i)); + /* Change clock divider if needed */ + pc87360_autodiv(client, i); + /* Clear bits and write new divider */ + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(i), + data->fan_status[i]); + } + if (FAN_CONFIG_CONTROL(data->fan_conf, i)) + data->pwm[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_PWM(i)); + } + + /* Voltages */ + for (i = 0; i < data->innr; i++) { + data->in_status[i] = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + data->in_status[i]); + if ((data->in_status[i] & 0x81) == 0x81) { + data->in[i] = pc87360_read_value(data, LD_IN, + i, PC87365_REG_IN); + } + if (data->in_status[i] & 0x01) { + data->in_min[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MIN); + data->in_max[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MAX); + if (i >= 11) + data->in_crit[i-11] = + pc87360_read_value(data, LD_IN, + i, PC87365_REG_TEMP_CRIT); + } + } + if (data->innr) { + data->in_alarms = pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS1) + | ((pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS2) + & 0x07) << 8); + data->vid = (data->vid_conf & 0xE0) ? + pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_VID) : 0x1F; + } + + /* Temperatures */ + for (i = 0; i < data->tempnr; i++) { + data->temp_status[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + data->temp_status[i]); + if ((data->temp_status[i] & 0x81) == 0x81) { + data->temp[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP); + } + if (data->temp_status[i] & 0x01) { + data->temp_min[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MIN); + data->temp_max[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MAX); + data->temp_crit[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_CRIT); + } + } + if (data->tempnr) { + data->temp_alarms = pc87360_read_value(data, LD_TEMP, + NO_BANK, PC87365_REG_TEMP_ALARMS) + & 0x3F; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init pc87360_init(void) +{ + int i; + + if (pc87360_find(0x2e, &devid, extra_isa) + && pc87360_find(0x4e, &devid, extra_isa)) { + printk(KERN_WARNING "pc87360: PC8736x not detected, " + "module not inserted.\n"); + return -ENODEV; + } + + /* Arbitrarily pick one of the addresses */ + for (i = 0; i < 3; i++) { + if (extra_isa[i] != 0x0000) { + normal_isa[0] = extra_isa[i]; + break; + } + } + + if (normal_isa[0] == 0x0000) { + printk(KERN_WARNING "pc87360: No active logical device, " + "module not inserted.\n"); + return -ENODEV; + } + + return i2c_add_driver(&pc87360_driver); +} + +static void __exit pc87360_exit(void) +{ + i2c_del_driver(&pc87360_driver); +} + + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("PC8736x hardware monitor"); +MODULE_LICENSE("GPL"); + +module_init(pc87360_init); +module_exit(pc87360_exit); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c new file mode 100644 index 00000000000..6bbfc8fb4f1 --- /dev/null +++ b/drivers/hwmon/sis5595.c @@ -0,0 +1,817 @@ +/* + sis5595.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (C) 1998 - 2001 Frodo Looijaard , + Kyösti Mälkki , and + Mark D. Studebaker + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + SiS southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c + + Supports following revisions: + Version PCI ID PCI Revision + 1 1039/0008 AF or less + 2 1039/0008 B0 or greater + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 5598 0008 5597/5598 + 630 0008 0630 + 645 0008 0645 + 730 0008 0730 + 735 0008 0735 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static u16 force_addr; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(sis5595); + +/* Many SIS5595 constants specified below */ + +/* Length of ISA address segment */ +#define SIS5595_EXTENT 8 +/* PCI Config Registers */ +#define SIS5595_REVISION_REG 0x08 +#define SIS5595_BASE_REG 0x68 +#define SIS5595_PIN_REG 0x7A +#define SIS5595_ENABLE_REG 0x7B + +/* Where are the ISA address/data registers relative to the base address */ +#define SIS5595_ADDR_REG_OFFSET 5 +#define SIS5595_DATA_REG_OFFSET 6 + +/* The SIS5595 registers */ +#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define SIS5595_REG_IN(nr) (0x20 + (nr)) + +#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) +#define SIS5595_REG_FAN(nr) (0x28 + (nr)) + +/* On the first version of the chip, the temp registers are separate. + On the second version, + TEMP pin is shared with IN4, configured in PCI register 0x7A. + The registers are the same as well. + OVER and HYST are really MAX and MIN. */ + +#define REV2MIN 0xb0 +#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN(4) : 0x27 +#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MAX(4) : 0x39 +#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MIN(4) : 0x3a + +#define SIS5595_REG_CONFIG 0x40 +#define SIS5595_REG_ALARM1 0x41 +#define SIS5595_REG_ALARM2 0x42 +#define SIS5595_REG_FANDIV 0x47 + +/* Conversions. Limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm <= 0) + return 255; + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-54.12C to +157.53C) + REG: 0.83C/bit + 52.12, two's complement */ +static inline int TEMP_FROM_REG(s8 val) +{ + return val * 830 + 52120; +} +static inline s8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -54120, 157530) ; + return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; +} + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static inline u8 DIV_TO_REG(int val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} +#define DIV_FROM_REG(val) (1 << (val)) + +/* For the SIS5595, we need to keep some data in memory. That + data is pointed to by sis5595_list[NR]->data. The structure itself is + dynamically allocated, at the time when the new sis5595 client is + allocated. */ +struct sis5595_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + char maxins; /* == 3 if temp enabled, otherwise == 4 */ + u8 revision; /* Reg. value */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ + +static int sis5595_attach_adapter(struct i2c_adapter *adapter); +static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind); +static int sis5595_detach_client(struct i2c_client *client); + +static int sis5595_read_value(struct i2c_client *client, u8 register); +static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value); +static struct sis5595_data *sis5595_update_device(struct device *dev); +static void sis5595_init_client(struct i2c_client *client); + +static struct i2c_driver sis5595_driver = { + .owner = THIS_MODULE, + .name = "sis5595", + .id = I2C_DRIVERID_SIS5595, + .flags = I2C_DF_NOTIFY, + .attach_adapter = sis5595_attach_adapter, + .detach_client = sis5595_detach_client, +}; + +/* 4 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst); + +/* 2 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long min; + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + reg = sis5595_read_value(client, SIS5595_REG_FANDIV); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + sis5595_write_value(client, SIS5595_REG_FANDIV, reg); + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} +static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div); +static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This is called when the module is loaded */ +static int sis5595_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, sis5595_detect); +} + +int sis5595_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int err = 0; + int i; + struct i2c_client *new_client; + struct sis5595_data *data; + char val; + u16 a; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) + goto exit; + + if (force_addr) + address = force_addr & ~(SIS5595_EXTENT - 1); + /* Reserve the ISA region */ + if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { + err = -EBUSY; + goto exit; + } + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) + goto exit_release; + if ((a & ~(SIS5595_EXTENT - 1)) != address) + /* doesn't work for some chips? */ + goto exit_release; + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { + goto exit_release; + } + if ((val & 0x80) == 0) { + if (PCIBIOS_SUCCESSFUL != + pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, + val | 0x80)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) + goto exit_release; + if ((val & 0x80) == 0) + /* doesn't work for some chips! */ + goto exit_release; + } + + if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct sis5595_data)); + + new_client = &data->client; + new_client->addr = address; + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->adapter = adapter; + new_client->driver = &sis5595_driver; + new_client->flags = 0; + + /* Check revision and pin registers to determine whether 4 or 5 voltages */ + pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); + /* 4 voltages, 1 temp */ + data->maxins = 3; + if (data->revision >= REV2MIN) { + pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); + if (!(val & 0x80)) + /* 5 voltages, no temps */ + data->maxins = 4; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the SIS5595 chip */ + sis5595_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 2; i++) { + data->fan_min[i] = sis5595_read_value(new_client, + SIS5595_REG_FAN_MIN(i)); + } + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + if (data->maxins == 4) { + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + } + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->maxins == 3) { + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + } + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, SIS5595_EXTENT); +exit: + return err; +} + +static int sis5595_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if (i2c_is_isa_client(client)) + release_region(client->addr, SIS5595_EXTENT); + + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +/* ISA access must be locked explicitly. */ +static int sis5595_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return res; +} + +static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return 0; +} + +/* Called when we have found a new SIS5595. */ +static void sis5595_init_client(struct i2c_client *client) +{ + u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); + if (!(config & 0x01)) + sis5595_write_value(client, SIS5595_REG_CONFIG, + (config & 0xf7) | 0x01); +} + +static struct sis5595_data *sis5595_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + for (i = 0; i <= data->maxins; i++) { + data->in[i] = + sis5595_read_value(client, SIS5595_REG_IN(i)); + data->in_min[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MIN(i)); + data->in_max[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) { + data->fan[i] = + sis5595_read_value(client, SIS5595_REG_FAN(i)); + data->fan_min[i] = + sis5595_read_value(client, + SIS5595_REG_FAN_MIN(i)); + } + if (data->maxins == 3) { + data->temp = + sis5595_read_value(client, SIS5595_REG_TEMP); + data->temp_over = + sis5595_read_value(client, SIS5595_REG_TEMP_OVER); + data->temp_hyst = + sis5595_read_value(client, SIS5595_REG_TEMP_HYST); + } + i = sis5595_read_value(client, SIS5595_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + sis5595_read_value(client, SIS5595_REG_ALARM1) | + (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static struct pci_device_id sis5595_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); + +static int blacklist[] __devinitdata = { + PCI_DEVICE_ID_SI_540, + PCI_DEVICE_ID_SI_550, + PCI_DEVICE_ID_SI_630, + PCI_DEVICE_ID_SI_645, + PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_735, + PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but + that ID shows up in other chips so we + use the 5511 ID for recognition */ + PCI_DEVICE_ID_SI_5597, + PCI_DEVICE_ID_SI_5598, + 0 }; + +static int __devinit sis5595_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int *i; + int addr = 0; + + for (i = blacklist; *i != 0; i++) { + struct pci_dev *dev; + dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); + if (dev) { + dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + pci_dev_put(dev); + return -ENODEV; + } + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, SIS5595_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(SIS5595_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + + s_bridge = pci_dev_get(dev); + if (i2c_add_driver(&sis5595_driver)) { + pci_dev_put(s_bridge); + s_bridge = NULL; + } + + /* Always return failure here. This is to allow other drivers to bind + * to this pci device. We don't really want to have control over the + * pci device, we only wanted to read as few register values from it. + */ + return -ENODEV; +} + +static struct pci_driver sis5595_pci_driver = { + .name = "sis5595", + .id_table = sis5595_pci_ids, + .probe = sis5595_pci_probe, +}; + +static int __init sm_sis5595_init(void) +{ + return pci_register_driver(&sis5595_pci_driver); +} + +static void __exit sm_sis5595_exit(void) +{ + pci_unregister_driver(&sis5595_pci_driver); + if (s_bridge != NULL) { + i2c_del_driver(&sis5595_driver); + pci_dev_put(s_bridge); + s_bridge = NULL; + } +} + +MODULE_AUTHOR("Aurelien Jarno "); +MODULE_DESCRIPTION("SiS 5595 Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_sis5595_init); +module_exit(sm_sis5595_exit); diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c new file mode 100644 index 00000000000..251ac265955 --- /dev/null +++ b/drivers/hwmon/smsc47b397.c @@ -0,0 +1,352 @@ +/* + smsc47b397.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B397-NC Super-I/O chip. + + Author/Maintainer: Mark M. Hoffman + Copyright (C) 2004 Utilitek Systems, Inc. + + derived in part from smsc47m1.c: + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47b397 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .probe = normal_i2c, /* cheat */ + .ignore = normal_i2c, /* cheat */ + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* select superio logical device */ +static inline void superio_select(int ld) +{ + superio_outb(0x07, ld); +} + +static inline void superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_DEVID 0x20 +#define SUPERIO_REG_DEVREV 0x21 +#define SUPERIO_REG_BASE_MSB 0x60 +#define SUPERIO_REG_BASE_LSB 0x61 +#define SUPERIO_REG_LD8 0x08 + +#define SMSC_EXTENT 0x02 + +/* 0 <= nr <= 3 */ +static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; +#define SMSC47B397_REG_TEMP(nr) (smsc47b397_reg_temp[(nr)]) + +/* 0 <= nr <= 3 */ +#define SMSC47B397_REG_FAN_LSB(nr) (0x28 + 2 * (nr)) +#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) + +struct smsc47b397_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + unsigned long last_updated; /* in jiffies */ + int valid; + + /* register values */ + u16 fan[4]; + u8 temp[4]; +}; + +static int smsc47b397_read_value(struct i2c_client *client, u8 reg) +{ + struct smsc47b397_data *data = i2c_get_clientdata(client); + int res; + + down(&data->lock); + outb(reg, client->addr); + res = inb_p(client->addr + 1); + up(&data->lock); + return res; +} + +static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47b397_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + dev_dbg(&client->dev, "starting device update...\n"); + + /* 4 temperature inputs, 4 fan inputs */ + for (i = 0; i < 4; i++) { + data->temp[i] = smsc47b397_read_value(client, + SMSC47B397_REG_TEMP(i)); + + /* must read LSB first */ + data->fan[i] = smsc47b397_read_value(client, + SMSC47B397_REG_FAN_LSB(i)); + data->fan[i] |= smsc47b397_read_value(client, + SMSC47B397_REG_FAN_MSB(i)) << 8; + } + + data->last_updated = jiffies; + data->valid = 1; + + dev_dbg(&client->dev, "... device update complete\n"); + } + + up(&data->update_lock); + + return data; +} + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static int temp_from_reg(u8 reg) +{ + return (s8)reg * 1000; +} + +/* 0 <= nr <= 3 */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct smsc47b397_data *data = smsc47b397_update_device(dev); + return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); +} + +#define sysfs_temp(num) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) + +sysfs_temp(1); +sysfs_temp(2); +sysfs_temp(3); +sysfs_temp(4); + +#define device_create_file_temp(client, num) \ + device_create_file(&client->dev, &dev_attr_temp##num##_input) + +/* FAN: 1 RPM/bit + REG: count of 90kHz pulses / revolution */ +static int fan_from_reg(u16 reg) +{ + return 90000 * 60 / reg; +} + +/* 0 <= nr <= 3 */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47b397_data *data = smsc47b397_update_device(dev); + return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); +} + +#define sysfs_fan(num) \ +static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) + +sysfs_fan(1); +sysfs_fan(2); +sysfs_fan(3); +sysfs_fan(4); + +#define device_create_file_fan(client, num) \ + device_create_file(&client->dev, &dev_attr_fan##num##_input) + +static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind); + +static int smsc47b397_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47b397_detect); +} + +static int smsc47b397_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; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver smsc47b397_driver = { + .owner = THIS_MODULE, + .name = "smsc47b397", + .id = I2C_DRIVERID_SMSC47B397, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47b397_attach_adapter, + .detach_client = smsc47b397_detach_client, +}; + +static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind) +{ + struct i2c_client *new_client; + struct smsc47b397_data *data; + int err = 0; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47b397_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = addr; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47b397_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE); + + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + device_create_file_temp(new_client, 4); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + device_create_file_fan(new_client, 4); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(addr, SMSC_EXTENT); + return err; +} + +static int __init smsc47b397_find(unsigned int *addr) +{ + u8 id, rev; + + superio_enter(); + id = superio_inb(SUPERIO_REG_DEVID); + + if (id != 0x6f) { + superio_exit(); + return -ENODEV; + } + + rev = superio_inb(SUPERIO_REG_DEVREV); + + superio_select(SUPERIO_REG_LD8); + *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) + | superio_inb(SUPERIO_REG_BASE_LSB); + + printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " + "(base address 0x%04x, revision %u)\n", *addr, rev); + + superio_exit(); + return 0; +} + +static int __init smsc47b397_init(void) +{ + int ret; + + if ((ret = smsc47b397_find(normal_isa))) + return ret; + + return i2c_add_driver(&smsc47b397_driver); +} + +static void __exit smsc47b397_exit(void) +{ + i2c_del_driver(&smsc47b397_driver); +} + +MODULE_AUTHOR("Mark M. Hoffman "); +MODULE_DESCRIPTION("SMSC LPC47B397 driver"); +MODULE_LICENSE("GPL"); + +module_init(smsc47b397_init); +module_exit(smsc47b397_exit); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c new file mode 100644 index 00000000000..897117a7213 --- /dev/null +++ b/drivers/hwmon/smsc47m1.c @@ -0,0 +1,593 @@ +/* + smsc47m1.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x + Super-I/O chips. + + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + Ported to Linux 2.6 by Gabriele Gorla + and Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47m1 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* logical device for fans is 0x0A */ +#define superio_select() superio_outb(0x07, 0x0A) + +static inline void +superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_ACT 0x30 +#define SUPERIO_REG_BASE 0x60 +#define SUPERIO_REG_DEVID 0x20 + +/* Logical device registers */ + +#define SMSC_EXTENT 0x80 + +/* nr is 0 or 1 in the macros below */ +#define SMSC47M1_REG_ALARM 0x04 +#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) +#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) +#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) +#define SMSC47M1_REG_FANDIV 0x58 +#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) +#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) + +#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ + 983040/((192-(reg))*(div))) +#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ + 983040/(((reg)-(preload))*(div))) +#define DIV_FROM_REG(reg) (1 << (reg)) +#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) +#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) +#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) + +struct smsc47m1_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + u8 fan[2]; /* Register value */ + u8 fan_preload[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 alarms; /* Register encoding */ + u8 pwm[2]; /* Register value (bit 7 is enable) */ +}; + + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); +static int smsc47m1_find(int *address); +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); +static int smsc47m1_detach_client(struct i2c_client *client); + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg); +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init); + + +static struct i2c_driver smsc47m1_driver = { + .owner = THIS_MODULE, + .name = "smsc47m1", + .id = I2C_DRIVERID_SMSC47M1, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47m1_attach_adapter, + .detach_client = smsc47m1_detach_client, +}; + +/* nr is 0 or 1 in the callback functions below */ + +static ssize_t get_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + /* This chip (stupidly) stops monitoring fan speed if PWM is + enabled and duty cycle is 0%. This is fine if the monitoring + and control concern the same fan, but troublesome if they are + not (which could as well happen). */ + int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : + FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]), + data->fan_preload[nr]); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_min(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int rpm = MIN_FROM_REG(data->fan_preload[nr], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_div(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t get_pwm(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + long rpmdiv, val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); + + if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { + up(&data->update_lock); + return -EINVAL; + } + + data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + up(&data->update_lock); + + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long new_div = simple_strtol(buf, NULL, 10), tmp; + u8 old_div = DIV_FROM_REG(data->fan_div[nr]); + + if (new_div == old_div) /* No change */ + return count; + + down(&data->update_lock); + switch (new_div) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + up(&data->update_lock); + return -EINVAL; + } + + tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; + tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); + smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); + + /* Preserve fan min */ + tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + + new_div / 2) / new_div; + data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + up(&data->update_lock); + + return count; +} + +static ssize_t set_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + down(&data->update_lock); + data->pwm[nr] &= 0x81; /* Preserve additional bits */ + data->pwm[nr] |= PWM_TO_REG(val); + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + up(&data->update_lock); + + return count; +} + +static ssize_t set_pwm_en(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val != 0 && val != 1) + return -EINVAL; + + down(&data->update_lock); + data->pwm[nr] &= 0xFE; /* preserve the other bits */ + data->pwm[nr] |= !val; + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + up(&data->update_lock); + + return count; +} + +#define fan_present(offset) \ +static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan(dev, buf, offset - 1); \ +} \ +static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_pwm_en(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_en(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + get_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + get_fan##offset##_div, set_fan##offset##_div); \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + get_pwm##offset, set_pwm##offset); \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + get_pwm##offset##_en, set_pwm##offset##_en); + +fan_present(1); +fan_present(2); + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47m1_detect); +} + +static int smsc47m1_find(int *address) +{ + u8 val; + + superio_enter(); + val = superio_inb(SUPERIO_REG_DEVID); + + /* + * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id + * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" + * can do much more besides (device id 0x60). + */ + if (val == 0x51) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); + else if (val == 0x59) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); + else if (val == 0x5F) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); + else if (val == 0x60) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); + else { + superio_exit(); + return -ENODEV; + } + + superio_select(); + *address = (superio_inb(SUPERIO_REG_BASE) << 8) + | superio_inb(SUPERIO_REG_BASE + 1); + val = superio_inb(SUPERIO_REG_ACT); + if (*address == 0 || (val & 0x01) == 0) { + printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); + superio_exit(); + return -ENODEV; + } + + superio_exit(); + return 0; +} + +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct smsc47m1_data *data; + int err = 0; + int fan1, fan2, pwm1, pwm2; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47m1_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47m1_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); + init_MUTEX(&data->update_lock); + + /* If no function is properly configured, there's no point in + actually registering the chip. */ + fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) + == 0x05; + fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) + == 0x05; + pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) + == 0x04; + pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) + == 0x04; + if (!(fan1 || fan2 || pwm1 || pwm2)) { + dev_warn(&new_client->dev, "Device is not configured, will not use\n"); + err = -ENODEV; + goto error_free; + } + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + /* Some values (fan min, clock dividers, pwm registers) may be + needed before any update is triggered, so we better read them + at least once here. We don't usually do it that way, but in + this particular case, manually reading 5 registers out of 8 + doesn't make much sense and we're better using the existing + function. */ + smsc47m1_update_device(&new_client->dev, 1); + + if (fan1) { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } else + dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " + "skipping\n"); + + if (fan2) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } else + dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " + "skipping\n"); + + if (pwm1) { + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + } else + dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " + "skipping\n"); + if (pwm2) { + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + } else + dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " + "skipping\n"); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(address, SMSC_EXTENT); + return err; +} + +static int smsc47m1_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; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + res = inb_p(client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + return res; +} + +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + outb_p(value, client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); +} + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { + int i; + + for (i = 0; i < 2; i++) { + data->fan[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN(i)); + data->fan_preload[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN_PRELOAD(i)); + data->pwm[i] = smsc47m1_read_value(client, + SMSC47M1_REG_PWM(i)); + } + + i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + + data->alarms = smsc47m1_read_value(client, + SMSC47M1_REG_ALARM) >> 6; + /* Clear alarms if needed */ + if (data->alarms) + smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); + + data->last_updated = jiffies; + } + + up(&data->update_lock); + return data; +} + +static int __init sm_smsc47m1_init(void) +{ + if (smsc47m1_find(normal_isa)) { + return -ENODEV; + } + + return i2c_add_driver(&smsc47m1_driver); +} + +static void __exit sm_smsc47m1_exit(void) +{ + i2c_del_driver(&smsc47m1_driver); +} + +MODULE_AUTHOR("Mark D. Studebaker "); +MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_smsc47m1_init); +module_exit(sm_smsc47m1_exit); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c new file mode 100644 index 00000000000..164d4794839 --- /dev/null +++ b/drivers/hwmon/via686a.c @@ -0,0 +1,875 @@ +/* + via686a.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (c) 1998 - 2002 Frodo Looijaard , + Kyösti Mälkki , + Mark Studebaker , + and Bob Dougherty + (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + and Alex van Kaam .) + + 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. +*/ + +/* + Supports the Via VT82C686A, VT82C686B south bridges. + Reports all as a 686A. + Warning - only supports a single device. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static unsigned short force_addr = 0; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(via686a); + +/* + The Via 686a southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c +*/ + +/* Many VIA686A constants specified below */ + +/* Length of ISA address segment */ +#define VIA686A_EXTENT 0x80 +#define VIA686A_BASE_REG 0x70 +#define VIA686A_ENABLE_REG 0x74 + +/* The VIA686A registers */ +/* ins numbered 0-4 */ +#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) +#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) +#define VIA686A_REG_IN(nr) (0x22 + (nr)) + +/* fans numbered 1-2 */ +#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) +#define VIA686A_REG_FAN(nr) (0x28 + (nr)) + +/* temps numbered 1-3 */ +static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; +static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; +static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; +/* bits 7-6 */ +#define VIA686A_REG_TEMP_LOW1 0x4b +/* 2 = bits 5-4, 3 = bits 7-6 */ +#define VIA686A_REG_TEMP_LOW23 0x49 + +#define VIA686A_REG_ALARM1 0x41 +#define VIA686A_REG_ALARM2 0x42 +#define VIA686A_REG_FANDIV 0x47 +#define VIA686A_REG_CONFIG 0x40 +/* The following register sets temp interrupt mode (bits 1-0 for temp1, + 3-2 for temp2, 5-4 for temp3). Modes are: + 00 interrupt stays as long as value is out-of-range + 01 interrupt is cleared once register is read (default) + 10 comparator mode- like 00, but ignores hysteresis + 11 same as 00 */ +#define VIA686A_REG_TEMP_MODE 0x4b +/* We'll just assume that you want to set all 3 simultaneously: */ +#define VIA686A_TEMP_MODE_MASK 0x3F +#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 + +/* Conversions. Limit checking is only done on the TO_REG + variants. + +********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** + From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): + voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp + voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V + voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V + voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V + voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V + in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; + That is: + volts = (25*regVal+133)*factor + regVal = (volts/factor-133)/25 + (These conversions were contributed by Jonathan Teh Soon Yew + ) */ +static inline u8 IN_TO_REG(long val, int inNum) +{ + /* To avoid floating point, we multiply constants by 10 (100 for +12V). + Rounding is done (120500 is actually 133000 - 12500). + Remember that val is expressed in 0.001V/bit, which is why we divide + by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) + for the constants. */ + if (inNum <= 1) + return (u8) + SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); + else if (inNum == 2) + return (u8) + SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); + else if (inNum == 3) + return (u8) + SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); + else + return (u8) + SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); +} + +static inline long IN_FROM_REG(u8 val, int inNum) +{ + /* To avoid floating point, we multiply constants by 10 (100 for +12V). + We also multiply them by 1000 because we want 0.001V/bit for the + output value. Rounding is done. */ + if (inNum <= 1) + return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); + else if (inNum == 2) + return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); + else if (inNum == 3) + return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); + else + return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); +} + +/********* FAN RPM CONVERSIONS ********/ +/* Higher register values = slower fans (the fan's strobe gates a counter). + But this chip saturates back at 0, not at 255 like all the other chips. + So, 0 means 0 RPM */ +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 0; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); +} + +#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) + +/******** TEMP CONVERSIONS (Bob Dougherty) *********/ +/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) + if(temp<169) + return double(temp)*0.427-32.08; + else if(temp>=169 && temp<=202) + return double(temp)*0.582-58.16; + else + return double(temp)*0.924-127.33; + + A fifth-order polynomial fits the unofficial data (provided by Alex van + Kaam ) a bit better. It also give more reasonable + numbers on my machine (ie. they agree with what my BIOS tells me). + Here's the fifth-order fit to the 8-bit data: + temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + + (2000-10-25- RFD: thanks to Uwe Andersen for + finding my typos in this formula!) + + Alas, none of the elegant function-fit solutions will work because we + aren't allowed to use floating point in the kernel and doing it with + integers doesn't provide enough precision. So we'll do boring old + look-up table stuff. The unofficial data (see below) have effectively + 7-bit resolution (they are rounded to the nearest degree). I'm assuming + that the transfer function of the device is monotonic and smooth, so a + smooth function fit to the data will allow us to get better precision. + I used the 5th-order poly fit described above and solved for + VIA register values 0-255. I *10 before rounding, so we get tenth-degree + precision. (I could have done all 1024 values for our 10-bit readings, + but the function is very linear in the useful range (0-80 deg C), so + we'll just use linear interpolation for 10-bit readings.) So, tempLUT + is the temp at via register values 0-255: */ +static const long tempLUT[] = +{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, + -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, + -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, + -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, + -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, + -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, + -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, + 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, + 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, + 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, + 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, + 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, + 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, + 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, + 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, + 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, + 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, + 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, + 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, + 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, + 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, + 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 +}; + +/* the original LUT values from Alex van Kaam + (for via register values 12-240): +{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, +-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, +-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, +-3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, +12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, +22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, +33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, +45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, +61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, +85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; + + + Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed + an extra term for a good fit to these inverse data!) and then + solving for each temp value from -50 to 110 (the useable range for + this chip). Here's the fit: + viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) + Note that n=161: */ +static const u8 viaLUT[] = +{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, + 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, + 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, + 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, + 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, + 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, + 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, + 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, + 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240 +}; + +/* Converting temps to (8-bit) hyst and over registers + No interpolation here. + The +50 is because the temps start at -50 */ +static inline u8 TEMP_TO_REG(long val) +{ + return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : + (val < 0 ? val - 500 : val + 500) / 1000 + 50]; +} + +/* for 8-bit temperature hyst and over registers */ +#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) + +/* for 10-bit temperature readings */ +static inline long TEMP_FROM_REG10(u16 val) +{ + u16 eightBits = val >> 2; + u16 twoBits = val & 3; + + /* no interpolation for these */ + if (twoBits == 0 || eightBits == 255) + return TEMP_FROM_REG(eightBits); + + /* do some linear interpolation */ + return (tempLUT[eightBits] * (4 - twoBits) + + tempLUT[eightBits + 1] * twoBits) * 25; +} + +#define DIV_FROM_REG(val) (1 << (val)) +#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) + +/* For the VIA686A, we need to keep some data in memory. + The structure is dynamically allocated, at the same time when a new + via686a client is allocated. */ +struct via686a_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + u16 temp[3]; /* Register value 10 bit */ + u8 temp_over[3]; /* Register value */ + u8 temp_hyst[3]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ + +static int via686a_attach_adapter(struct i2c_adapter *adapter); +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); +static int via686a_detach_client(struct i2c_client *client); + +static inline int via686a_read_value(struct i2c_client *client, u8 reg) +{ + return (inb_p(client->addr + reg)); +} + +static inline void via686a_write_value(struct i2c_client *client, u8 reg, + u8 value) +{ + outb_p(value, client->addr + reg); +} + +static struct via686a_data *via686a_update_device(struct device *dev); +static void via686a_init_client(struct i2c_client *client); + +/* following are the sysfs callback functions */ + +/* 7 voltage sensors */ +static ssize_t show_in(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MIN(nr), + data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MAX(nr), + data->in_max[nr]); + up(&data->update_lock); + return count; +} +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); + +/* 3 temperatures */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); +} +static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); +} +static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); +} +static ssize_t set_temp_over(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over[nr] = TEMP_TO_REG(val); + via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], + data->temp_over[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_temp_hyst(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst[nr] = TEMP_TO_REG(val); + via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], + data->temp_hyst[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_offset(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t \ +show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_over(dev, buf, offset - 1); \ +} \ +static ssize_t \ +show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_hyst(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_over(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_hyst(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_over, set_temp_##offset##_over); \ +static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_hyst, set_temp_##offset##_hyst); + +show_temp_offset(1); +show_temp_offset(2); +show_temp_offset(3); + +/* 2 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", + FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); +} +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int old; + + down(&data->update_lock); + old = via686a_read_value(client, VIA686A_REG_FANDIV); + data->fan_div[nr] = DIV_TO_REG(val); + old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); + via686a_write_value(client, VIA686A_REG_FANDIV, old); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_div, set_fan_##offset##_div); + +show_fan_offset(1); +show_fan_offset(2); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* The driver. I choose to use type i2c_driver, as at is identical to both + smbus_driver and isa_driver, and clients could be of either kind */ +static struct i2c_driver via686a_driver = { + .owner = THIS_MODULE, + .name = "via686a", + .id = I2C_DRIVERID_VIA686A, + .flags = I2C_DF_NOTIFY, + .attach_adapter = via686a_attach_adapter, + .detach_client = via686a_detach_client, +}; + + +/* This is called when the module is loaded */ +static int via686a_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, via686a_detect); +} + +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct via686a_data *data; + int err = 0; + const char client_name[] = "via686a"; + u16 val; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) { + dev_err(&adapter->dev, + "via686a_detect called for an I2C bus adapter?!?\n"); + return 0; + } + + /* 8231 requires multiple of 256, we enforce that on 686 as well */ + if (force_addr) + address = force_addr & 0xFF00; + + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", + address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) + return -ENODEV; + } + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) + return -ENODEV; + if (!(val & 0x0001)) { + dev_warn(&adapter->dev, "enabling sensors\n"); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, + val | 0x0001)) + return -ENODEV; + } + + /* Reserve the ISA region */ + if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { + dev_err(&adapter->dev, "region 0x%x already in use!\n", + address); + return -ENODEV; + } + + if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct via686a_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &via686a_driver; + new_client->flags = 0; + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, 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 ERROR3; + + /* Initialize the VIA686A chip */ + via686a_init_client(new_client); + + /* Register sysfs hooks */ + 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_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +ERROR3: + kfree(data); +ERROR0: + release_region(address, VIA686A_EXTENT); + return err; +} + +static int via686a_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; + } + + release_region(client->addr, VIA686A_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* Called when we have found a new VIA686A. Set limits, etc. */ +static void via686a_init_client(struct i2c_client *client) +{ + u8 reg; + + /* Start monitoring */ + reg = via686a_read_value(client, VIA686A_REG_CONFIG); + via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); + + /* Configure temp interrupt mode for continuous-interrupt operation */ + via686a_write_value(client, VIA686A_REG_TEMP_MODE, + via686a_read_value(client, VIA686A_REG_TEMP_MODE) & + !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); +} + +static struct via686a_data *via686a_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 4; i++) { + data->in[i] = + via686a_read_value(client, VIA686A_REG_IN(i)); + data->in_min[i] = via686a_read_value(client, + VIA686A_REG_IN_MIN + (i)); + data->in_max[i] = + via686a_read_value(client, VIA686A_REG_IN_MAX(i)); + } + for (i = 1; i <= 2; i++) { + data->fan[i - 1] = + via686a_read_value(client, VIA686A_REG_FAN(i)); + data->fan_min[i - 1] = via686a_read_value(client, + VIA686A_REG_FAN_MIN(i)); + } + for (i = 0; i <= 2; i++) { + data->temp[i] = via686a_read_value(client, + VIA686A_REG_TEMP[i]) << 2; + data->temp_over[i] = + via686a_read_value(client, + VIA686A_REG_TEMP_OVER[i]); + data->temp_hyst[i] = + via686a_read_value(client, + VIA686A_REG_TEMP_HYST[i]); + } + /* add in lower 2 bits + temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 + temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 + temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 + */ + data->temp[0] |= (via686a_read_value(client, + VIA686A_REG_TEMP_LOW1) + & 0xc0) >> 6; + data->temp[1] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0x30) >> 4; + data->temp[2] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0xc0) >> 6; + + i = via686a_read_value(client, VIA686A_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + via686a_read_value(client, + VIA686A_REG_ALARM1) | + (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static struct pci_device_id via686a_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, via686a_pci_ids); + +static int __devinit via686a_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int addr = 0; + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "base address not set - upgrade BIOS " + "or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev, "No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + + 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, +}; + +static int __init sm_via686a_init(void) +{ + return pci_register_driver(&via686a_pci_driver); +} + +static void __exit sm_via686a_exit(void) +{ + 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 , " + "Mark Studebaker " + "and Bob Dougherty "); +MODULE_DESCRIPTION("VIA 686A Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_via686a_init); +module_exit(sm_via686a_exit); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c new file mode 100644 index 00000000000..8a40b6976e1 --- /dev/null +++ b/drivers/hwmon/w83627ehf.c @@ -0,0 +1,846 @@ +/* + w83627ehf - Driver for the hardware monitoring functionality of + the Winbond W83627EHF Super-I/O chip + Copyright (C) 2005 Jean Delvare + + Shamelessly ripped from the w83627hf driver + Copyright (C) 2003 Mark Studebaker + + Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help + in testing and debugging this driver. + + 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. + + + Supports the following chips: + + Chip #vin #fan #pwm #temp chip_id man_id + w83627ehf - 5 - 3 0x88 0x5ca3 + + This is a preliminary version of the driver, only supporting the + fan and temperature inputs. The chip does much more than that. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan + The actual ISA address is read from Super-I/O configuration space */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(w83627ehf); + +/* + * Super-I/O constants and functions + */ + +static int REG; /* The register to read/write */ +static int VAL; /* The value to read/write */ + +#define W83627EHF_LD_HWM 0x0b + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_W83627EHF_ID 0x8840 +#define SIO_ID_MASK 0xFFC0 + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(SIO_REG_LDSEL, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +/* + * ISA constants + */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define W83627EHF_REG_BANK 0x4E +#define W83627EHF_REG_CONFIG 0x40 +#define W83627EHF_REG_CHIP_ID 0x49 +#define W83627EHF_REG_MAN_ID 0x4F + +static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; +static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; + +#define W83627EHF_REG_TEMP1 0x27 +#define W83627EHF_REG_TEMP1_HYST 0x3a +#define W83627EHF_REG_TEMP1_OVER 0x39 +static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; +static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; +static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; +static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; + +/* Fan clock dividers are spread over the following five registers */ +#define W83627EHF_REG_FANDIV1 0x47 +#define W83627EHF_REG_FANDIV2 0x4B +#define W83627EHF_REG_VBAT 0x5D +#define W83627EHF_REG_DIODE 0x59 +#define W83627EHF_REG_SMI_OVT 0x4C + +/* + * Conversions + */ + +static inline unsigned int +fan_from_reg(u8 reg, unsigned int div) +{ + if (reg == 0 || reg == 255) + return 0; + return 1350000U / (reg * div); +} + +static inline unsigned int +div_from_reg(u8 reg) +{ + return 1 << reg; +} + +static inline int +temp1_from_reg(s8 reg) +{ + return reg * 1000; +} + +static inline s8 +temp1_to_reg(int temp) +{ + if (temp <= -128000) + return -128; + if (temp >= 127000) + return 127; + if (temp < 0) + return (temp - 500) / 1000; + return (temp + 500) / 1000; +} + +/* + * Data structures and manipulation thereof + */ + +struct w83627ehf_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ + u8 fan[5]; + u8 fan_min[5]; + u8 fan_div[5]; + u8 has_fan; /* some fan inputs can be disabled */ + s8 temp1; + s8 temp1_max; + s8 temp1_max_hyst; + s16 temp[2]; + s16 temp_max[2]; + s16 temp_max_hyst[2]; +}; + +static inline int is_word_sized(u16 reg) +{ + return (((reg & 0xff00) == 0x100 + || (reg & 0xff00) == 0x200) + && ((reg & 0x00ff) == 0x50 + || (reg & 0x00ff) == 0x53 + || (reg & 0x00ff) == 0x55)); +} + +/* We assume that the default bank is 0, thus the following two functions do + nothing for registers which live in bank 0. For others, they respectively + set the bank register to the correct value (before the register is + accessed), and back to 0 (afterwards). */ +static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); + } +} + +static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(0, client->addr + DATA_REG_OFFSET); + } +} + +static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int res, word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + res = inb_p(client->addr + DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); + } + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + + return res; +} + +static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, client->addr + DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + return 0; +} + +/* This function assumes that the caller holds data->update_lock */ +static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + u8 reg; + + switch (nr) { + case 0: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) + | ((data->fan_div[0] & 0x03) << 4); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) + | ((data->fan_div[0] & 0x04) << 3); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 1: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) + | ((data->fan_div[1] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) + | ((data->fan_div[1] & 0x04) << 4); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 2: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) + | ((data->fan_div[2] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) + | ((data->fan_div[2] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 3: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) + | (data->fan_div[3] & 0x03); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) + | ((data->fan_div[3] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); + break; + case 4: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) + | ((data->fan_div[4] & 0x03) << 3) + | ((data->fan_div[4] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + break; + } +} + +static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + /* Fan clock dividers */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); + data->fan_div[2] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + if (data->has_fan & ((1 << 3) | (1 << 4))) { + i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); + data->fan_div[3] = i & 0x03; + data->fan_div[4] = ((i >> 2) & 0x03) + | ((i >> 5) & 0x04); + } + if (data->has_fan & (1 << 3)) { + i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); + data->fan_div[3] |= (i >> 5) & 0x04; + } + + /* Measured fan speeds and limits */ + for (i = 0; i < 5; i++) { + if (!(data->has_fan & (1 << i))) + continue; + + data->fan[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN[i]); + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* If we failed to measure the fan speed and clock + divider can be increased, let's try that for next + time */ + if (data->fan[i] == 0xff + && data->fan_div[i] < 0x07) { + dev_dbg(&client->dev, "Increasing fan %d " + "clock divider from %u to %u\n", + i, div_from_reg(data->fan_div[i]), + div_from_reg(data->fan_div[i] + 1)); + data->fan_div[i]++; + w83627ehf_write_fan_div(client, i); + /* Preserve min limit if possible */ + if (data->fan_min[i] >= 2 + && data->fan_min[i] != 255) + w83627ehf_write_value(client, + W83627EHF_REG_FAN_MIN[i], + (data->fan_min[i] /= 2)); + } + } + + /* Measured temperatures and limits */ + data->temp1 = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1); + data->temp1_max = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_OVER); + data->temp1_max_hyst = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_HYST); + for (i = 0; i < 2; i++) { + data->temp[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP[i]); + data->temp_max[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_OVER[i]); + data->temp_max_hyst[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_HYST[i]); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ + +#define show_fan_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + fan_from_reg(data->reg[nr], \ + div_from_reg(data->fan_div[nr]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +show_fan_div(struct device *dev, char *buf, int nr) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + return sprintf(buf, "%u\n", + div_from_reg(data->fan_div[nr])); +} + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + unsigned int val = simple_strtoul(buf, NULL, 10); + unsigned int reg; + u8 new_div; + + down(&data->update_lock); + if (!val) { + /* No min limit, alarm disabled */ + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; /* No change */ + dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); + } else if ((reg = 1350000U / val) >= 128 * 255) { + /* Speed below this value cannot possibly be represented, + even with the highest divider (128) */ + data->fan_min[nr] = 254; + new_div = 7; /* 128 == (1 << 7) */ + dev_warn(dev, "fan%u low limit %u below minimum %u, set to " + "minimum\n", nr + 1, val, fan_from_reg(254, 128)); + } else if (!reg) { + /* Speed above this value cannot possibly be represented, + even with the lowest divider (1) */ + data->fan_min[nr] = 1; + new_div = 0; /* 1 == (1 << 0) */ + dev_warn(dev, "fan%u low limit %u above maximum %u, set to " + "maximum\n", nr + 1, val, fan_from_reg(1, 1)); + } else { + /* Automatically pick the best divider, i.e. the one such + that the min limit will correspond to a register value + in the 96..192 range */ + new_div = 0; + while (reg > 192 && new_div < 7) { + reg >>= 1; + new_div++; + } + data->fan_min[nr] = reg; + } + + /* Write both the fan clock divider (if it changed) and the new + fan min (unconditionally) */ + if (new_div != data->fan_div[nr]) { + if (new_div > data->fan_div[nr]) + data->fan[nr] >>= (data->fan_div[nr] - new_div); + else + data->fan[nr] <<= (new_div - data->fan_div[nr]); + + dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", + nr + 1, div_from_reg(data->fan_div[nr]), + div_from_reg(new_div)); + data->fan_div[nr] = new_div; + w83627ehf_write_fan_div(client, nr); + } + w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t \ +show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan(dev, buf, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_reg_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_min(dev, buf, offset-1); \ +} \ +static ssize_t \ +store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_reg_fan##offset##_min, \ + store_reg_fan##offset##_min); + +#define sysfs_fan_div_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_reg_fan##offset##_div, NULL); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_div_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_div_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); +sysfs_fan_div_offset(3); +sysfs_fan_offset(4); +sysfs_fan_min_offset(4); +sysfs_fan_div_offset(4); +sysfs_fan_offset(5); +sysfs_fan_min_offset(5); +sysfs_fan_div_offset(5); + +#define show_temp1_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ +} +show_temp1_reg(temp1); +show_temp1_reg(temp1_max); +show_temp1_reg(temp1_max_hyst); + +#define store_temp1_reg(REG, reg) \ +static ssize_t \ +store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp1_##reg = temp1_to_reg(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ + data->temp1_##reg); \ + up(&data->update_lock); \ + return count; \ +} +store_temp1_reg(OVER, max); +store_temp1_reg(HYST, max_hyst); + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, + show_temp1_max, store_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, + show_temp1_max_hyst, store_temp1_max_hyst); + +#define show_temp_reg(reg) \ +static ssize_t \ +show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + LM75_TEMP_FROM_REG(data->reg[nr])); \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, temp_max); +store_temp_reg(HYST, temp_max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp(dev, buf, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_reg_temp##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t \ +show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_##reg(dev, buf, offset - 2); \ +} \ +static ssize_t \ +store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_temp_##reg(dev, buf, count, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_reg_temp##offset##_##reg, \ + store_reg_temp##offset##_##reg); + +sysfs_temp_offset(2); +sysfs_temp_reg_offset(max, 2); +sysfs_temp_reg_offset(max_hyst, 2); +sysfs_temp_offset(3); +sysfs_temp_reg_offset(max, 3); +sysfs_temp_reg_offset(max_hyst, 3); + +/* + * Driver and client management + */ + +static struct i2c_driver w83627ehf_driver; + +static void w83627ehf_init_client(struct i2c_client *client) +{ + int i; + u8 tmp; + + /* Start monitoring is needed */ + tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); + if (!(tmp & 0x01)) + w83627ehf_write_value(client, W83627EHF_REG_CONFIG, + tmp | 0x01); + + /* Enable temp2 and temp3 if needed */ + for (i = 0; i < 2; i++) { + tmp = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_CONFIG[i]); + if (tmp & 0x01) + w83627ehf_write_value(client, + W83627EHF_REG_TEMP_CONFIG[i], + tmp & 0xfe); + } +} + +static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct w83627ehf_data *data; + int i, err = 0; + + if (!i2c_is_isa_adapter(adapter)) + return 0; + + if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + err = -EBUSY; + goto exit; + } + + if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct w83627ehf_data)); + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + init_MUTEX(&data->lock); + client->adapter = adapter; + client->driver = &w83627ehf_driver; + client->flags = 0; + + strlcpy(client->name, "w83627ehf", 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(client))) + goto exit_free; + + /* Initialize the chip */ + w83627ehf_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 5; i++) + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* It looks like fan4 and fan5 pins can be alternatively used + as fan on/off switches */ + data->has_fan = 0x07; /* fan1, fan2 and fan3 */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + if (i & (1 << 2)) + data->has_fan |= (1 << 3); + if (i & (1 << 0)) + data->has_fan |= (1 << 4); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_fan1_input); + device_create_file(&client->dev, &dev_attr_fan1_min); + device_create_file(&client->dev, &dev_attr_fan1_div); + device_create_file(&client->dev, &dev_attr_fan2_input); + device_create_file(&client->dev, &dev_attr_fan2_min); + device_create_file(&client->dev, &dev_attr_fan2_div); + device_create_file(&client->dev, &dev_attr_fan3_input); + device_create_file(&client->dev, &dev_attr_fan3_min); + device_create_file(&client->dev, &dev_attr_fan3_div); + + if (data->has_fan & (1 << 3)) { + device_create_file(&client->dev, &dev_attr_fan4_input); + device_create_file(&client->dev, &dev_attr_fan4_min); + device_create_file(&client->dev, &dev_attr_fan4_div); + } + if (data->has_fan & (1 << 4)) { + device_create_file(&client->dev, &dev_attr_fan5_input); + device_create_file(&client->dev, &dev_attr_fan5_min); + device_create_file(&client->dev, &dev_attr_fan5_div); + } + + device_create_file(&client->dev, &dev_attr_temp1_input); + device_create_file(&client->dev, &dev_attr_temp1_max); + device_create_file(&client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&client->dev, &dev_attr_temp2_input); + device_create_file(&client->dev, &dev_attr_temp2_max); + device_create_file(&client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&client->dev, &dev_attr_temp3_input); + device_create_file(&client->dev, &dev_attr_temp3_max); + device_create_file(&client->dev, &dev_attr_temp3_max_hyst); + + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, REGION_LENGTH); +exit: + return err; +} + +static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83627ehf_detect); +} + +static int w83627ehf_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; + } + release_region(client->addr, REGION_LENGTH); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver w83627ehf_driver = { + .owner = THIS_MODULE, + .name = "w83627ehf", + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627ehf_attach_adapter, + .detach_client = w83627ehf_detach_client, +}; + +static int __init w83627ehf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + superio_enter(); + + val = (superio_inb(SIO_REG_DEVID) << 8) + | superio_inb(SIO_REG_DEVID + 1); + if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627EHF_LD_HWM); + val = (superio_inb(SIO_REG_ADDR) << 8) + | superio_inb(SIO_REG_ADDR + 1); + *address = val & ~(REGION_LENGTH - 1); + if (*address == 0) { + superio_exit(); + return -ENODEV; + } + + /* Activate logical device if needed */ + val = superio_inb(SIO_REG_ENABLE); + if (!(val & 0x01)) + superio_outb(SIO_REG_ENABLE, val | 0x01); + + superio_exit(); + return 0; +} + +static int __init sensors_w83627ehf_init(void) +{ + if (w83627ehf_find(0x2e, &normal_isa[0]) + && w83627ehf_find(0x4e, &normal_isa[0])) + return -ENODEV; + + return i2c_add_driver(&w83627ehf_driver); +} + +static void __exit sensors_w83627ehf_exit(void) +{ + i2c_del_driver(&w83627ehf_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("W83627EHF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627ehf_init); +module_exit(sensors_w83627ehf_exit); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c new file mode 100644 index 00000000000..bd87a42e068 --- /dev/null +++ b/drivers/hwmon/w83627hf.c @@ -0,0 +1,1511 @@ +/* + w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2003 Frodo Looijaard , + Philip Edelbrock , + and Mark Studebaker + Ported to 2.6 by Bernhard C. Schrenk + + 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. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) + w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) + w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) + w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + + For other winbond chips, and for i2c support in the above chips, + use w83781d.c. + + Note: automatic ("cruise") fan control for 697, 637 & 627thf not + supported yet. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +static u16 force_addr; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); +static u8 force_i2c = 0x1f; +module_param(force_i2c, byte, 0); +MODULE_PARM_DESC(force_i2c, + "Initialize the i2c address of the sensors"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); + +static int init = 1; +module_param(init, bool, 0); +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); + +/* modified from kernel/include/traps.c */ +static int REG; /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +static int VAL; /* The value to read/write */ + +/* logical device numbers for superio_select (below) */ +#define W83627HF_LD_FDC 0x00 +#define W83627HF_LD_PRT 0x01 +#define W83627HF_LD_UART1 0x02 +#define W83627HF_LD_UART2 0x03 +#define W83627HF_LD_KBC 0x05 +#define W83627HF_LD_CIR 0x06 /* w83627hf only */ +#define W83627HF_LD_GAME 0x07 +#define W83627HF_LD_MIDI 0x07 +#define W83627HF_LD_GPIO1 0x07 +#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ +#define W83627HF_LD_GPIO2 0x08 +#define W83627HF_LD_GPIO3 0x09 +#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ +#define W83627HF_LD_ACPI 0x0a +#define W83627HF_LD_HWM 0x0b + +#define DEVID 0x20 /* Register: Device ID */ + +#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ +#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ +#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(DEV, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define W627_DEVID 0x52 +#define W627THF_DEVID 0x82 +#define W697_DEVID 0x60 +#define W637_DEVID 0x70 +#define WINB_ACT_REG 0x30 +#define WINB_BASE_REG 0x60 +/* Constants specified below */ + +/* Length of ISA address segment */ +#define WINB_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define W83781D_ADDR_REG_OFFSET 5 +#define W83781D_DATA_REG_OFFSET 6 + +/* The W83781D registers */ +/* The W83782D registers for nr=7,8 are in bank 5 */ +#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0x554 + (((nr) - 7) * 2))) +#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0x555 + (((nr) - 7) * 2))) +#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0x550 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) +#define W83781D_REG_FAN(nr) (0x27 + (nr)) + +#define W83781D_REG_TEMP2_CONFIG 0x152 +#define W83781D_REG_TEMP3_CONFIG 0x252 +#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ + ((nr == 2) ? (0x0150) : \ + (0x27))) +#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ + ((nr == 2) ? (0x153) : \ + (0x3A))) +#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ + ((nr == 2) ? (0x155) : \ + (0x39))) + +#define W83781D_REG_BANK 0x4E + +#define W83781D_REG_CONFIG 0x40 +#define W83781D_REG_ALARM1 0x41 +#define W83781D_REG_ALARM2 0x42 +#define W83781D_REG_ALARM3 0x450 + +#define W83781D_REG_IRQ 0x4C +#define W83781D_REG_BEEP_CONFIG 0x4D +#define W83781D_REG_BEEP_INTS1 0x56 +#define W83781D_REG_BEEP_INTS2 0x57 +#define W83781D_REG_BEEP_INTS3 0x453 + +#define W83781D_REG_VID_FANDIV 0x47 + +#define W83781D_REG_CHIPID 0x49 +#define W83781D_REG_WCHIPID 0x58 +#define W83781D_REG_CHIPMAN 0x4F +#define W83781D_REG_PIN 0x4B + +#define W83781D_REG_VBAT 0x5D + +#define W83627HF_REG_PWM1 0x5A +#define W83627HF_REG_PWM2 0x5B +#define W83627HF_REG_PWMCLK12 0x5C + +#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ +#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ +#define W83627THF_REG_PWM3 0x11 /* 637HF too */ + +#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ + +static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; +static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, + W83627THF_REG_PWM3 }; +#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ + regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) + +#define W83781D_REG_I2C_ADDR 0x48 +#define W83781D_REG_I2C_SUBADDR 0x4A + +/* Sensor selection */ +#define W83781D_REG_SCFG1 0x5D +static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; +#define W83781D_REG_SCFG2 0x59 +static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; +#define W83781D_DEFAULT_BETA 3435 + +/* Conversions. Limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, + 254); +} + +#define TEMP_MIN (-128000) +#define TEMP_MAX ( 127000) + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static u8 TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); + ntemp += (ntemp<0 ? -500 : 500); + return (u8)(ntemp / 1000); +} + +static int TEMP_FROM_REG(u8 reg) +{ + return (s8)reg * 1000; +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) + +#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) + +#define BEEP_MASK_FROM_REG(val) (val) +#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) +#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) +#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 DIV_TO_REG(long val) +{ + int i; + val = SENSORS_LIMIT(val, 1, 128) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +/* For each registered chip, we need to keep some data in memory. That + data is pointed to by w83627hf_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new client is allocated. */ +struct w83627hf_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + struct i2c_client *lm75; /* for secondary I2C addresses */ + /* pointer to array of 2 subclients */ + + u8 in[9]; /* Register value */ + u8 in_max[9]; /* Register value */ + u8 in_min[9]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; + u8 temp_max; /* Register value */ + u8 temp_max_hyst; /* Register value */ + u16 temp_add[2]; /* Register value */ + u16 temp_max_add[2]; /* Register value */ + u16 temp_max_hyst_add[2]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u32 beep_mask; /* Register encoding, combined */ + u8 beep_enable; /* Boolean */ + u8 pwm[3]; /* Register value */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. + Other Betas unimplemented */ + u8 vrm; + u8 vrm_ovt; /* Register value, 627thf & 637hf only */ +}; + + +static int w83627hf_attach_adapter(struct i2c_adapter *adapter); +static int w83627hf_detect(struct i2c_adapter *adapter, int address, + int kind); +static int w83627hf_detach_client(struct i2c_client *client); + +static int w83627hf_read_value(struct i2c_client *client, u16 register); +static int w83627hf_write_value(struct i2c_client *client, u16 register, + u16 value); +static struct w83627hf_data *w83627hf_update_device(struct device *dev); +static void w83627hf_init_client(struct i2c_client *client); + +static struct i2c_driver w83627hf_driver = { + .owner = THIS_MODULE, + .name = "w83627hf", + .id = I2C_DRIVERID_W83627HF, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627hf_attach_adapter, + .detach_client = w83627hf_detach_client, +}; + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ +} +show_in_reg(in) +show_in_reg(in_min) +show_in_reg(in_max) + +#define store_in_reg(REG, reg) \ +static ssize_t \ +store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627hf_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + \ + up(&data->update_lock); \ + return count; \ +} +store_in_reg(MIN, min) +store_in_reg(MAX, max) + +#define sysfs_in_offset(offset) \ +static ssize_t \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + +#define sysfs_in_reg_offset(reg, offset) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_##reg (dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_in_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_regs_in_##reg##offset, store_regs_in_##reg##offset); + +#define sysfs_in_offsets(offset) \ +sysfs_in_offset(offset) \ +sysfs_in_reg_offset(min, offset) \ +sysfs_in_reg_offset(max, offset) + +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); + +/* use a different set of functions for in0 */ +static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) +{ + long in0; + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + in0 = (long)((reg * 488 + 70000 + 50) / 100); + else + /* use VRM8 (standard) calculation */ + in0 = (long)IN_FROM_REG(reg); + + return sprintf(buf,"%ld\n", in0); +} + +static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in[0]); +} + +static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_min[0]); +} + +static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_max[0]); +} + +static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_min[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); + up(&data->update_lock); + return count; +} + +static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_max[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); +static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, + show_regs_in_min0, store_regs_in_min0); +static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, + show_regs_in_max0, store_regs_in_max0); + +#define device_create_file_in(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +device_create_file(&client->dev, &dev_attr_in##offset##_min); \ +device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +#define show_fan_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + FAN_FROM_REG(data->reg[nr-1], \ + (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr - 1] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_regs_fan_min##offset, store_regs_fan_min##offset); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); + +#define device_create_file_fan(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ +} while (0) + +#define show_temp_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + return sprintf(buf,"%ld\n", \ + (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ + } else { /* TEMP1 */ \ + return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ + } \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627hf_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg##_add[nr-2]); \ + } else { /* TEMP1 */ \ + data->temp_##reg = TEMP_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg); \ + } \ + \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, max); +store_temp_reg(HYST, max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_##reg (dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_temp_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); + +#define sysfs_temp_offsets(offset) \ +sysfs_temp_offset(offset) \ +sysfs_temp_reg_offset(max, offset) \ +sysfs_temp_reg_offset(max_hyst, offset) + +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); + +#define device_create_file_temp(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ +} while (0) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms) + +#define show_beep_reg(REG, reg) \ +static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ +} +show_beep_reg(ENABLE, enable) +show_beep_reg(MASK, mask) + +#define BEEP_ENABLE 0 /* Store beep_enable */ +#define BEEP_MASK 1 /* Store beep_mask */ + +static ssize_t +store_beep_reg(struct device *dev, const char *buf, size_t count, + int update_mask) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val, val2; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val); + w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + val2 = (data->beep_mask >> 8) & 0x7f; + } else { /* We are storing beep_enable */ + val2 = + w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + data->beep_enable = BEEP_ENABLE_TO_REG(val); + } + + w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + + up(&data->update_lock); + return count; +} + +#define sysfs_beep(REG, reg) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_beep_##reg(dev, attr, buf); \ +} \ +static ssize_t \ +store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_beep_reg(dev, buf, count, BEEP_##REG); \ +} \ +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ + show_regs_beep_##reg, store_regs_beep_##reg); + +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); + +#define device_create_file_beep(client) \ +do { \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask); \ +} while (0) + +static ssize_t +show_fan_div_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", + (long) DIV_FROM_REG(data->fan_div[nr - 1])); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + unsigned long min; + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(val); + + reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + reg = (w83627hf_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83627hf_write_value(client, W83781D_REG_VBAT, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_div(offset) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_regs_fan_div_##offset, store_regs_fan_div_##offset); + +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); + +#define device_create_file_fan_div(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +static ssize_t +show_pwm_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); +} + +static ssize_t +store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (data->type == w83627thf) { + /* bits 0-3 are reserved in 627THF */ + data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; + w83627hf_write_value(client, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr - 1] | + (w83627hf_read_value(client, + W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); + } else { + data->pwm[nr - 1] = PWM_TO_REG(val); + w83627hf_write_value(client, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr - 1]); + } + + up(&data->update_lock); + return count; +} + +#define sysfs_pwm(offset) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_pwm_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_regs_pwm_##offset, store_regs_pwm_##offset); + +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwm(3); + +#define device_create_file_pwm(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset); \ +} while (0) + +static ssize_t +show_sensor_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); +} + +static ssize_t +store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val, tmp; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); + w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case 2: /* 3904 */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); + w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr - 1]); + data->sens[nr - 1] = val; + break; + default: + dev_err(&client->dev, + "Invalid sensor type %ld; must be 1, 2, or %d\n", + (long) val, W83781D_DEFAULT_BETA); + break; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_sensor(offset) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_sensor_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_sensor_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_regs_sensor_##offset, store_regs_sensor_##offset); + +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); + +#define device_create_file_sensor(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ +} while (0) + + +/* This function is called when: + * w83627hf_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and w83627hf_driver is still present) */ +static int w83627hf_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, w83627hf_detect); +} + +static int w83627hf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + + superio_enter(); + val= superio_inb(DEVID); + if(val != W627_DEVID && + val != W627THF_DEVID && + val != W697_DEVID && + val != W637_DEVID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627HF_LD_HWM); + val = (superio_inb(WINB_BASE_REG) << 8) | + superio_inb(WINB_BASE_REG + 1); + *address = val & ~(WINB_EXTENT - 1); + if (*address == 0 && force_addr == 0) { + superio_exit(); + return -ENODEV; + } + if (force_addr) + *address = force_addr; /* so detect will get called */ + + superio_exit(); + return 0; +} + +int w83627hf_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int val; + struct i2c_client *new_client; + struct w83627hf_data *data; + int err = 0; + const char *client_name = ""; + + if (!i2c_is_isa_adapter(adapter)) { + err = -ENODEV; + goto ERROR0; + } + + if(force_addr) + address = force_addr & ~(WINB_EXTENT - 1); + + if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { + err = -EBUSY; + goto ERROR0; + } + + if(force_addr) { + printk("w83627hf.o: forcing ISA address 0x%04X\n", address); + superio_enter(); + superio_select(W83627HF_LD_HWM); + superio_outb(WINB_BASE_REG, address >> 8); + superio_outb(WINB_BASE_REG+1, address & 0xff); + superio_exit(); + } + + superio_enter(); + val= superio_inb(DEVID); + if(val == W627_DEVID) + kind = w83627hf; + else if(val == W697_DEVID) + kind = w83697hf; + else if(val == W627THF_DEVID) + kind = w83627thf; + else if(val == W637_DEVID) + kind = w83637hf; + else { + dev_info(&adapter->dev, + "Unsupported chip (dev_id=0x%02X).\n", val); + goto ERROR1; + } + + superio_select(W83627HF_LD_HWM); + if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) + superio_outb(WINB_ACT_REG, 1); + superio_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 w83627hf_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct w83627hf_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83627hf_driver; + new_client->flags = 0; + + + if (kind == w83627hf) { + client_name = "w83627hf"; + } else if (kind == w83627thf) { + client_name = "w83627thf"; + } else if (kind == w83697hf) { + client_name = "w83697hf"; + } else if (kind == w83637hf) { + client_name = "w83637hf"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + 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 ERROR2; + + data->lm75 = NULL; + + /* Initialize the chip */ + w83627hf_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); + data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); + data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + if (kind != w83697hf) + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + if (kind != w83627thf && kind != w83637hf) { + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + } + device_create_file_in(new_client, 7); + device_create_file_in(new_client, 8); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + if (kind != w83697hf) + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + if (kind != w83697hf) + device_create_file_temp(new_client, 3); + + if (kind != w83697hf) + device_create_file_vid(new_client); + + if (kind != w83697hf) + device_create_file_vrm(new_client); + + device_create_file_fan_div(new_client, 1); + device_create_file_fan_div(new_client, 2); + if (kind != w83697hf) + device_create_file_fan_div(new_client, 3); + + device_create_file_alarms(new_client); + + device_create_file_beep(new_client); + + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); + if (kind == w83627thf || kind == w83637hf) + device_create_file_pwm(new_client, 3); + + device_create_file_sensor(new_client, 1); + device_create_file_sensor(new_client, 2); + if (kind != w83697hf) + device_create_file_sensor(new_client, 3); + + return 0; + + ERROR2: + kfree(data); + ERROR1: + release_region(address, WINB_EXTENT); + ERROR0: + return err; +} + +static int w83627hf_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; + } + + release_region(client->addr, WINB_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +/* + ISA access must always be locked explicitly! + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + would slow down the W83781D access and should not be necessary. + There are some ugly typecasts here, but the good news is - they should + nowhere else be necessary! */ +static int w83627hf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int res, word_sized; + + down(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(client->addr + + W83781D_DATA_REG_OFFSET); + } + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + up(&data->lock); + return res; +} + +static int w83627thf_read_gpio5(struct i2c_client *client) +{ + int res = 0xff, sel; + + superio_enter(); + superio_select(W83627HF_LD_GPIO5); + + /* Make sure these GPIO pins are enabled */ + if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { + dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); + goto exit; + } + + /* Make sure the pins are configured for input + There must be at least five (VRM 9), and possibly 6 (VRM 10) */ + sel = superio_inb(W83627THF_GPIO5_IOSR); + if ((sel & 0x1f) != 0x1f) { + dev_dbg(&client->dev, "GPIO5 not configured for VID " + "function\n"); + goto exit; + } + + dev_info(&client->dev, "Reading VID from GPIO5\n"); + res = superio_inb(W83627THF_GPIO5_DR) & sel; + +exit: + superio_exit(); + return res; +} + +static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int word_sized; + + down(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, + client->addr + W83781D_DATA_REG_OFFSET); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + up(&data->lock); + return 0; +} + +/* Called when we have found a new W83781D. It should set limits, etc. */ +static void w83627hf_init_client(struct i2c_client *client) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int i; + int type = data->type; + u8 tmp; + + if(init) { + /* save this register */ + i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); + /* Restore the register and disable power-on abnormal beep. + This saves FAN 1/2/3 input/output values set by BIOS. */ + w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + /* Disable master beep-enable (reset turns it on). + Individual beeps should be reset to off but for some reason + disabling this bit helps some people not get beeped */ + w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + + /* Minimize conflicts with other winbond i2c-only clients... */ + /* disable i2c subclients... how to disable main i2c client?? */ + /* force i2c address to relatively uncommon address */ + w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); + w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); + + /* Read VID only once */ + if (w83627hf == data->type || w83637hf == data->type) { + int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); + int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); + data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); + } else if (w83627thf == data->type) { + data->vid = w83627thf_read_gpio5(client) & 0x3f; + } + + /* Read VRM & OVT Config only once */ + if (w83627thf == data->type || w83637hf == data->type) { + data->vrm_ovt = + w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; + } else { + /* Convert VID to voltage based on default VRM */ + data->vrm = i2c_which_vrm(); + } + + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = W83781D_DEFAULT_BETA; + } else { + if (w83627hf_read_value + (client, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if ((type == w83697hf) && (i == 2)) + break; + } + + if(init) { + /* Enable temp2 */ + tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83697hf) { + tmp = w83627hf_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83627hf_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + + if (type == w83627hf) { + /* enable PWM2 control (can't hurt since PWM reg + should have been reset to 0xff) */ + w83627hf_write_value(client, W83627HF_REG_PWMCLK12, + 0x19); + } + /* enable comparator mode for temp2 and temp3 so + alarm indication will work correctly */ + i = w83627hf_read_value(client, W83781D_REG_IRQ); + if (!(i & 0x40)) + w83627hf_write_value(client, W83781D_REG_IRQ, + i | 0x40); + } + + /* Start monitoring */ + w83627hf_write_value(client, W83781D_REG_CONFIG, + (w83627hf_read_value(client, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); +} + +static struct w83627hf_data *w83627hf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 8; i++) { + /* skip missing sensors */ + if (((data->type == w83697hf) && (i == 1)) || + ((data->type == w83627thf || data->type == w83637hf) + && (i == 4 || i == 5))) + continue; + data->in[i] = + w83627hf_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83627hf_read_value(client, + W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83627hf_read_value(client, + W83781D_REG_IN_MAX(i)); + } + for (i = 1; i <= 3; i++) { + data->fan[i - 1] = + w83627hf_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83627hf_read_value(client, + W83781D_REG_FAN_MIN(i)); + } + for (i = 1; i <= 3; i++) { + u8 tmp = w83627hf_read_value(client, + W836X7HF_REG_PWM(data->type, i)); + /* bits 0-3 are reserved in 627THF */ + if (data->type == w83627thf) + tmp &= 0xf0; + data->pwm[i - 1] = tmp; + if(i == 2 && + (data->type == w83627hf || data->type == w83697hf)) + break; + } + + data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); + data->temp_max = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); + data->temp_max_hyst = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); + data->temp_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP(2)); + data->temp_max_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); + data->temp_max_hyst_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); + if (data->type != w83697hf) { + data->temp_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP(3)); + data->temp_max_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); + data->temp_max_hyst_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); + } + + i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83627hf_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; + } + i = w83627hf_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (i >> 5) & 0x04; + data->alarms = + w83627hf_read_value(client, W83781D_REG_ALARM1) | + (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | + (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); + i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beep_mask = ((i & 0x7f) << 8) | + w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | + w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_w83627hf_init(void) +{ + int addr; + + if (w83627hf_find(0x2e, &addr) + && w83627hf_find(0x4e, &addr)) { + return -ENODEV; + } + normal_isa[0] = addr; + + return i2c_add_driver(&w83627hf_driver); +} + +static void __exit sensors_w83627hf_exit(void) +{ + i2c_del_driver(&w83627hf_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark Studebaker "); +MODULE_DESCRIPTION("W83627HF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627hf_init); +module_exit(sensors_w83627hf_exit); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c new file mode 100644 index 00000000000..0bb131ce09e --- /dev/null +++ b/drivers/hwmon/w83781d.c @@ -0,0 +1,1632 @@ +/* + w83781d.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard , + Philip Edelbrock , + and Mark Studebaker + + 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. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + as99127f 7 3 0 3 0x31 0x12c3 yes no + as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no + w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes + w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) + w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes + w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* 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 int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); +I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + +static int init = 1; +module_param(init, bool, 0); +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); + +/* Constants specified below */ + +/* Length of ISA address segment */ +#define W83781D_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define W83781D_ADDR_REG_OFFSET 5 +#define W83781D_DATA_REG_OFFSET 6 + +/* The W83781D registers */ +/* The W83782D registers for nr=7,8 are in bank 5 */ +#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0x554 + (((nr) - 7) * 2))) +#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0x555 + (((nr) - 7) * 2))) +#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0x550 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) +#define W83781D_REG_FAN(nr) (0x27 + (nr)) + +#define W83781D_REG_BANK 0x4E +#define W83781D_REG_TEMP2_CONFIG 0x152 +#define W83781D_REG_TEMP3_CONFIG 0x252 +#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ + ((nr == 2) ? (0x0150) : \ + (0x27))) +#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ + ((nr == 2) ? (0x153) : \ + (0x3A))) +#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ + ((nr == 2) ? (0x155) : \ + (0x39))) + +#define W83781D_REG_CONFIG 0x40 +#define W83781D_REG_ALARM1 0x41 +#define W83781D_REG_ALARM2 0x42 +#define W83781D_REG_ALARM3 0x450 /* not on W83781D */ + +#define W83781D_REG_IRQ 0x4C +#define W83781D_REG_BEEP_CONFIG 0x4D +#define W83781D_REG_BEEP_INTS1 0x56 +#define W83781D_REG_BEEP_INTS2 0x57 +#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ + +#define W83781D_REG_VID_FANDIV 0x47 + +#define W83781D_REG_CHIPID 0x49 +#define W83781D_REG_WCHIPID 0x58 +#define W83781D_REG_CHIPMAN 0x4F +#define W83781D_REG_PIN 0x4B + +/* 782D/783S only */ +#define W83781D_REG_VBAT 0x5D + +/* PWM 782D (1-4) and 783S (1-2) only */ +#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ + /* on which is which; */ +#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ + /* However 782d is probably wrong. */ +#define W83781D_REG_PWM3 0x5E +#define W83781D_REG_PWM4 0x5F +#define W83781D_REG_PWMCLK12 0x5C +#define W83781D_REG_PWMCLK34 0x45C +static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, + W83781D_REG_PWM3, W83781D_REG_PWM4 +}; + +#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) + +#define W83781D_REG_I2C_ADDR 0x48 +#define W83781D_REG_I2C_SUBADDR 0x4A + +/* The following are undocumented in the data sheets however we + received the information in an email from Winbond tech support */ +/* Sensor selection - not on 781d */ +#define W83781D_REG_SCFG1 0x5D +static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; + +#define W83781D_REG_SCFG2 0x59 +static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; + +#define W83781D_DEFAULT_BETA 3435 + +/* RT Table registers */ +#define W83781D_REG_RT_IDX 0x50 +#define W83781D_REG_RT_VAL 0x51 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) +#define IN_FROM_REG(val) (((val) * 16) / 10) + +static inline u8 +FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ + ((val) == 255 ? 0 : \ + 1350000 / ((val) * (div)))) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ + : (val)) / 1000, 0, 0xff)) +#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) + +#define PWM_FROM_REG(val) (val) +#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) +#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ + (val) ^ 0x7fff : (val)) +#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ + (~(val)) & 0x7fff : (val) & 0xffffff) + +#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) +#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 +DIV_TO_REG(long val, enum chips type) +{ + int i; + val = SENSORS_LIMIT(val, 1, + ((type == w83781d + || type == as99127f) ? 8 : 128)) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +/* There are some complications in a module like this. First off, W83781D chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + W83781D chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the W83781D at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered W83781D, we need to keep some data in memory. That + data is pointed to by w83781d_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new w83781d client is + allocated. */ +struct w83781d_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + struct i2c_client *lm75[2]; /* for secondary I2C addresses */ + /* array of 2 pointers to subclients */ + + u8 in[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; + u8 temp_max; /* Register value */ + u8 temp_max_hyst; /* Register value */ + u16 temp_add[2]; /* Register value */ + u16 temp_max_add[2]; /* Register value */ + u16 temp_max_hyst_add[2]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u32 beep_mask; /* Register encoding, combined */ + u8 beep_enable; /* Boolean */ + u8 pwm[4]; /* Register value */ + u8 pwmenable[4]; /* Boolean */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. + Other Betas unimplemented */ + u8 vrm; +}; + +static int w83781d_attach_adapter(struct i2c_adapter *adapter); +static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); +static int w83781d_detach_client(struct i2c_client *client); + +static int w83781d_read_value(struct i2c_client *client, u16 register); +static int w83781d_write_value(struct i2c_client *client, u16 register, + u16 value); +static struct w83781d_data *w83781d_update_device(struct device *dev); +static void w83781d_init_client(struct i2c_client *client); + +static struct i2c_driver w83781d_driver = { + .owner = THIS_MODULE, + .name = "w83781d", + .id = I2C_DRIVERID_W83781D, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83781d_attach_adapter, + .detach_client = w83781d_detach_client, +}; + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \ +} +show_in_reg(in); +show_in_reg(in_min); +show_in_reg(in_max); + +#define store_in_reg(REG, reg) \ +static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10) / 10; \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ + \ + up(&data->update_lock); \ + return count; \ +} +store_in_reg(MIN, min); +store_in_reg(MAX, max); + +#define sysfs_in_offset(offset) \ +static ssize_t \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + +#define sysfs_in_reg_offset(reg, offset) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_##reg (dev, buf, offset); \ +} \ +static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_in_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); + +#define sysfs_in_offsets(offset) \ +sysfs_in_offset(offset); \ +sysfs_in_reg_offset(min, offset); \ +sysfs_in_reg_offset(max, offset); + +sysfs_in_offsets(0); +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); + +#define device_create_file_in(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +device_create_file(&client->dev, &dev_attr_in##offset##_min); \ +device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +#define show_fan_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr - 1] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset); \ +} \ +static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); + +#define device_create_file_fan(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ +} while (0) + +#define show_temp_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + 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)); \ + } \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + s32 val; \ + \ + val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + 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 */ \ + data->temp_##reg = TEMP_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg); \ + } \ + \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, max); +store_temp_reg(HYST, max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_##reg (dev, buf, offset); \ +} \ +static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_temp_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); + +#define sysfs_temp_offsets(offset) \ +sysfs_temp_offset(offset); \ +sysfs_temp_reg_offset(max, offset); \ +sysfs_temp_reg_offset(max_hyst, offset); + +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); + +#define device_create_file_temp(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ +} while (0) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static +DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid); +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} + +static +DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm); +static ssize_t +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static +DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms); +static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type)); +} +static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_ENABLE_FROM_REG(data->beep_enable)); +} + +#define BEEP_ENABLE 0 /* Store beep_enable */ +#define BEEP_MASK 1 /* Store beep_mask */ + +static ssize_t +store_beep_reg(struct device *dev, const char *buf, size_t count, + int update_mask) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, val2; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val, data->type); + w83781d_write_value(client, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + + if ((data->type != w83781d) && (data->type != as99127f)) { + w83781d_write_value(client, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + } + + val2 = (data->beep_mask >> 8) & 0x7f; + } else { /* We are storing beep_enable */ + val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + data->beep_enable = BEEP_ENABLE_TO_REG(val); + } + + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + + up(&data->update_lock); + return count; +} + +#define sysfs_beep(REG, reg) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_beep_##reg(dev, attr, buf); \ +} \ +static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_beep_reg(dev, buf, count, BEEP_##REG); \ +} \ +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); + +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); + +#define device_create_file_beep(client) \ +do { \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask); \ +} while (0) + +static ssize_t +show_fan_div_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long) DIV_FROM_REG(data->fan_div[nr - 1])); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + unsigned long min; + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(val, data->type); + + reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + /* w83781d and as99127f don't have extended divisor bits */ + if (data->type != w83781d && data->type != as99127f) { + reg = (w83781d_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83781d_write_value(client, W83781D_REG_VBAT, reg); + } + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_div(offset) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); + +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); + +#define device_create_file_fan_div(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +static ssize_t +show_pwm_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); +} + +static ssize_t +show_pwmenable_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); +} + +static ssize_t +store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm[nr - 1] = PWM_TO_REG(val); + w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t +store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, reg; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 0: + case 1: + reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); + w83781d_write_value(client, W83781D_REG_PWMCLK12, + (reg & 0xf7) | (val << 3)); + + reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, + (reg & 0xef) | (!val << 4)); + + data->pwmenable[nr - 1] = val; + break; + + default: + up(&data->update_lock); + return -EINVAL; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_pwm(offset) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_pwm_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_regs_pwm_##offset, store_regs_pwm_##offset); + +#define sysfs_pwmenable(offset) \ +static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwmenable_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_pwmenable_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); + +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ +sysfs_pwm(3); +sysfs_pwm(4); + +#define device_create_file_pwm(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset); \ +} while (0) + +#define device_create_file_pwmenable(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \ +} while (0) + +static ssize_t +show_sensor_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); +} + +static ssize_t +store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, tmp; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case 2: /* 3904 */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr - 1]); + data->sens[nr - 1] = val; + break; + default: + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", + (long) val, W83781D_DEFAULT_BETA); + break; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_sensor(offset) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_sensor_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_sensor_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); + +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); + +#define device_create_file_sensor(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ +} while (0) + +/* This function is called when: + * w83781d_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and w83781d_driver is still present) */ +static int +w83781d_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83781d_detect); +} + +/* Assumes that adapter is of I2C, not ISA variety. + * OTHERWISE DON'T CALL THIS + */ +static int +w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, + struct i2c_client *new_client) +{ + int i, val1 = 0, id; + int err; + const char *client_name = ""; + struct w83781d_data *data = i2c_get_clientdata(new_client); + + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "Invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -EINVAL; + goto ERROR_SC_1; + } + } + w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) << 4)); + data->lm75[0]->addr = force_subclients[2]; + } else { + val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); + data->lm75[0]->addr = 0x48 + (val1 & 0x07); + } + + if (kind != w83783s) { + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); + + if (force_subclients[0] == id && + force_subclients[1] == address) { + data->lm75[1]->addr = force_subclients[3]; + } else { + data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); + } + if (data->lm75[0]->addr == data->lm75[1]->addr) { + dev_err(&new_client->dev, + "Duplicate addresses 0x%x for subclients.\n", + data->lm75[0]->addr); + err = -EBUSY; + goto ERROR_SC_2; + } + } + + if (kind == w83781d) + client_name = "w83781d subclient"; + else if (kind == w83782d) + client_name = "w83782d subclient"; + else if (kind == w83783s) + client_name = "w83783s subclient"; + else if (kind == w83627hf) + client_name = "w83627hf subclient"; + else if (kind == as99127f) + client_name = "as99127f subclient"; + + for (i = 0; i <= 1; i++) { + /* store all data in w83781d */ + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &w83781d_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->name, client_name, + I2C_NAME_SIZE); + if ((err = i2c_attach_client(data->lm75[i]))) { + dev_err(&new_client->dev, "Subclient %d " + "registration at address 0x%x " + "failed.\n", i, data->lm75[i]->addr); + if (i == 1) + goto ERROR_SC_3; + goto ERROR_SC_2; + } + if (kind == w83783s) + break; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); +ERROR_SC_2: + if (NULL != data->lm75[1]) + kfree(data->lm75[1]); +ERROR_SC_1: + if (NULL != data->lm75[0]) + kfree(data->lm75[0]); +ERROR_SC_0: + return err; +} + +static int +w83781d_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i = 0, val1 = 0, val2; + struct i2c_client *new_client; + struct w83781d_data *data; + int err; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + enum vendor { winbond, asus } vendid; + + if (!is_isa + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -EINVAL; + goto ERROR0; + } + + /* Prevent users from forcing a kind for a bus it isn't supposed + to possibly be on */ + if (is_isa && (kind == as99127f || kind == w83783s)) { + dev_err(&adapter->dev, + "Cannot force I2C-only chip for ISA address 0x%02x.\n", + address); + err = -EINVAL; + goto ERROR0; + } + + if (is_isa) + if (!request_region(address, W83781D_EXTENT, + w83781d_driver.name)) { + dev_dbg(&adapter->dev, "Request of region " + "0x%x-0x%x for w83781d failed\n", address, + address + W83781D_EXTENT - 1); + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i + || inb_p(address + 3) != i + || inb_p(address + 7) != i) { + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 1\n"); + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + val2 = inb_p(address + 5) & 0x7f; + if (val2 != (~i & 0x7f)) { + outb_p(i, address + 5); + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 2 (0x%x != " + "0x%x at 0x%x)\n", val2, ~i & 0x7f, + address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* 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 w83781d_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct w83781d_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83781d_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + /* The w8378?d may be stuck in some other bank than bank 0. This may + make reading other information impossible. Specify a force=... or + force_*=... parameter, and the Winbond will be reset to the right + bank. */ + if (kind < 0) { + if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) { + dev_dbg(&new_client->dev, "Detection failed at step " + "3\n"); + err = -ENODEV; + goto ERROR2; + } + val1 = w83781d_read_value(new_client, W83781D_REG_BANK); + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + /* Check for Winbond or Asus ID if in bank 0 */ + if ((!(val1 & 0x07)) && + (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) + || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { + dev_dbg(&new_client->dev, "Detection failed at step " + "4\n"); + err = -ENODEV; + goto ERROR2; + } + /* If Winbond SMBus, check address at 0x48. + Asus doesn't support, except for as99127f rev.2 */ + if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || + ((val1 & 0x80) && (val2 == 0x5c)))) { + if (w83781d_read_value + (new_client, W83781D_REG_I2C_ADDR) != address) { + dev_dbg(&new_client->dev, "Detection failed " + "at step 5\n"); + err = -ENODEV; + goto ERROR2; + } + } + } + + /* We have either had a force parameter, or we have already detected the + Winbond. Put it now into bank 0 and Vendor ID High Byte */ + w83781d_write_value(new_client, W83781D_REG_BANK, + (w83781d_read_value(new_client, + W83781D_REG_BANK) & 0x78) | + 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + /* get vendor ID */ + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + if (val2 == 0x5c) + vendid = winbond; + else if (val2 == 0x12) + vendid = asus; + else { + dev_dbg(&new_client->dev, "Chip was made by neither " + "Winbond nor Asus?\n"); + err = -ENODEV; + goto ERROR2; + } + + val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); + if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) + kind = w83781d; + else if (val1 == 0x30 && vendid == winbond) + kind = w83782d; + else if (val1 == 0x40 && vendid == winbond && !is_isa + && address == 0x2d) + kind = w83783s; + else if (val1 == 0x21 && vendid == winbond) + kind = w83627hf; + else if (val1 == 0x31 && !is_isa && address >= 0x28) + kind = as99127f; + else { + if (kind == 0) + dev_warn(&new_client->dev, "Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -EINVAL; + goto ERROR2; + } + } + + if (kind == w83781d) { + client_name = "w83781d"; + } else if (kind == w83782d) { + client_name = "w83782d"; + } else if (kind == w83783s) { + client_name = "w83783s"; + } else if (kind == w83627hf) { + client_name = "w83627hf"; + } else if (kind == as99127f) { + client_name = "as99127f"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + + 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 ERROR2; + + /* attach secondary i2c lm75-like clients */ + if (!is_isa) { + if ((err = w83781d_detect_subclients(adapter, address, + kind, new_client))) + goto ERROR3; + } else { + data->lm75[0] = NULL; + data->lm75[1] = NULL; + } + + /* Initialize the chip */ + w83781d_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 1; i <= 3; i++) { + data->fan_min[i - 1] = w83781d_read_value(new_client, + W83781D_REG_FAN_MIN(i)); + } + if (kind != w83781d && kind != as99127f) + for (i = 0; i < 4; i++) + data->pwmenable[i] = 1; + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + if (kind != w83783s) + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + if (kind != as99127f && kind != w83781d && kind != w83783s) { + device_create_file_in(new_client, 7); + device_create_file_in(new_client, 8); + } + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + if (kind != w83783s) + device_create_file_temp(new_client, 3); + + device_create_file_vid(new_client); + device_create_file_vrm(new_client); + + device_create_file_fan_div(new_client, 1); + device_create_file_fan_div(new_client, 2); + device_create_file_fan_div(new_client, 3); + + device_create_file_alarms(new_client); + + device_create_file_beep(new_client); + + if (kind != w83781d && kind != as99127f) { + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); + device_create_file_pwmenable(new_client, 2); + } + if (kind == w83782d && !is_isa) { + device_create_file_pwm(new_client, 3); + device_create_file_pwm(new_client, 4); + } + + if (kind != as99127f && kind != w83781d) { + device_create_file_sensor(new_client, 1); + device_create_file_sensor(new_client, 2); + if (kind != w83783s) + device_create_file_sensor(new_client, 3); + } + + return 0; + +ERROR3: + i2c_detach_client(new_client); +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, W83781D_EXTENT); +ERROR0: + return err; +} + +static int +w83781d_detach_client(struct i2c_client *client) +{ + int err; + + if (i2c_is_isa_client(client)) + release_region(client->addr, W83781D_EXTENT); + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if (i2c_get_clientdata(client)==NULL) { + /* subclients */ + kfree(client); + } else { + /* main client */ + kfree(i2c_get_clientdata(client)); + } + + return 0; +} + +/* The SMBus locks itself, usually, but nothing may access the Winbond between + bank switches. ISA access must always be locked explicitly! + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + would slow down the W83781D access and should not be necessary. + There are some ugly typecasts here, but the good news is - they should + nowhere else be necessary! */ +static int +w83781d_read_value(struct i2c_client *client, u16 reg) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int res, word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(client->addr + + W83781D_DATA_REG_OFFSET); + } + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + res = i2c_smbus_read_byte_data(client, reg & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x50: /* TEMP */ + res = swab16(i2c_smbus_read_word_data(cl, 0)); + break; + case 0x52: /* CONFIG */ + res = i2c_smbus_read_byte_data(cl, 1); + break; + case 0x53: /* HYST */ + res = swab16(i2c_smbus_read_word_data(cl, 2)); + break; + case 0x55: /* OVER */ + default: + res = swab16(i2c_smbus_read_word_data(cl, 3)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return res; +} + +static int +w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + i2c_smbus_write_byte_data(client, reg & 0xff, + value & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x52: /* CONFIG */ + i2c_smbus_write_byte_data(cl, 1, value & 0xff); + break; + case 0x53: /* HYST */ + i2c_smbus_write_word_data(cl, 2, swab16(value)); + break; + case 0x55: /* OVER */ + i2c_smbus_write_word_data(cl, 3, swab16(value)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return 0; +} + +/* Called when we have found a new W83781D. It should set limits, etc. */ +static void +w83781d_init_client(struct i2c_client *client) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int i, p; + int type = data->type; + u8 tmp; + + if (init && type != as99127f) { /* this resets registers we don't have + documentation for on the as99127f */ + /* save these registers */ + i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + p = w83781d_read_value(client, W83781D_REG_PWMCLK12); + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); + /* Restore the registers and disable power-on abnormal beep. + This saves FAN 1/2/3 input/output values set by BIOS. */ + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + w83781d_write_value(client, W83781D_REG_PWMCLK12, p); + /* Disable master beep-enable (reset turns it on). + Individual beep_mask should be reset to off but for some reason + disabling this bit helps some people not get beeped */ + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + + data->vrm = i2c_which_vrm(); + + if ((type != w83781d) && (type != as99127f)) { + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = W83781D_DEFAULT_BETA; + } else { + if (w83781d_read_value + (client, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if (type == w83783s && i == 2) + break; + } + } + + if (init && type != as99127f) { + /* Enable temp2 */ + tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83783s) { + tmp = w83781d_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83781d_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + + if (type != w83781d) { + /* enable comparator mode for temp2 and temp3 so + alarm indication will work correctly */ + i = w83781d_read_value(client, W83781D_REG_IRQ); + if (!(i & 0x40)) + w83781d_write_value(client, W83781D_REG_IRQ, + i | 0x40); + } + } + + /* Start monitoring */ + w83781d_write_value(client, W83781D_REG_CONFIG, + (w83781d_read_value(client, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); +} + +static struct w83781d_data *w83781d_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(dev, "Starting device update\n"); + + for (i = 0; i <= 8; i++) { + if (data->type == w83783s && i == 1) + continue; /* 783S has no in1 */ + data->in[i] = + w83781d_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83781d_read_value(client, W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83781d_read_value(client, W83781D_REG_IN_MAX(i)); + if ((data->type != w83782d) + && (data->type != w83627hf) && (i == 6)) + break; + } + for (i = 1; i <= 3; i++) { + data->fan[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); + } + if (data->type != w83781d && data->type != as99127f) { + for (i = 1; i <= 4; i++) { + data->pwm[i - 1] = + w83781d_read_value(client, + W83781D_REG_PWM(i)); + if ((data->type != w83782d + || i2c_is_isa_client(client)) + && i == 2) + break; + } + /* Only PWM2 can be disabled */ + data->pwmenable[1] = (w83781d_read_value(client, + W83781D_REG_PWMCLK12) & 0x08) >> 3; + } + + data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); + data->temp_max = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); + data->temp_max_hyst = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); + data->temp_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP(2)); + data->temp_max_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); + data->temp_max_hyst_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); + if (data->type != w83783s) { + data->temp_add[1] = + w83781d_read_value(client, W83781D_REG_TEMP(3)); + data->temp_max_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_OVER(3)); + data->temp_max_hyst_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_HYST(3)); + } + i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + data->vid = i & 0x0f; + data->vid |= (w83781d_read_value(client, + W83781D_REG_CHIPID) & 0x01) << 4; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; + if ((data->type != w83781d) && (data->type != as99127f)) { + i = w83781d_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + } + data->alarms = + w83781d_read_value(client, + W83781D_REG_ALARM1) + + (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); + if ((data->type == w83782d) || (data->type == w83627hf)) { + data->alarms |= + w83781d_read_value(client, + W83781D_REG_ALARM3) << 16; + } + i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beep_mask = ((i & 0x7f) << 8) + + w83781d_read_value(client, W83781D_REG_BEEP_INTS1); + if ((data->type != w83781d) && (data->type != as99127f)) { + data->beep_mask |= + w83781d_read_value(client, + W83781D_REG_BEEP_INTS3) << 16; + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init +sensors_w83781d_init(void) +{ + return i2c_add_driver(&w83781d_driver); +} + +static void __exit +sensors_w83781d_exit(void) +{ + i2c_del_driver(&w83781d_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark Studebaker "); +MODULE_DESCRIPTION("W83781D driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83781d_init); +module_exit(sensors_w83781d_exit); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c new file mode 100644 index 00000000000..4469d52aba4 --- /dev/null +++ b/drivers/hwmon/w83l785ts.c @@ -0,0 +1,328 @@ +/* + * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2004 Jean Delvare + * + * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made + * by Winbond. It reports a single external temperature with a 1 deg + * resolution and a 3 deg accuracy. Datasheet can be obtained from + * Winbond's website at: + * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf + * + * Ported to Linux 2.6 by Wolfgang Ziegler and Jean Delvare + * . + * + * Thanks to James Bolt for benchmarking the read + * error handling mechanism. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* How many retries on register read error */ +#define MAX_RETRIES 5 + +/* + * Address to scan + * Address is fully defined internally and cannot be changed. + */ + +static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(w83l785ts); + +/* + * The W83L785TS-S registers + * Manufacturer ID is 0x5CA3 for Winbond. + */ + +#define W83L785TS_REG_MAN_ID1 0x4D +#define W83L785TS_REG_MAN_ID2 0x4C +#define W83L785TS_REG_CHIP_ID 0x4E +#define W83L785TS_REG_CONFIG 0x40 +#define W83L785TS_REG_TYPE 0x52 +#define W83L785TS_REG_TEMP 0x27 +#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ + +/* + * Conversions + * The W83L785TS-S uses signed 8-bit values. + */ + +#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) + +/* + * Functions declaration + */ + +static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); +static int w83l785ts_detect(struct i2c_adapter *adapter, int address, + int kind); +static int w83l785ts_detach_client(struct i2c_client *client); +static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); +static struct w83l785ts_data *w83l785ts_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver w83l785ts_driver = { + .owner = THIS_MODULE, + .name = "w83l785ts", + .id = I2C_DRIVERID_W83L785TS, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83l785ts_attach_adapter, + .detach_client = w83l785ts_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct w83l785ts_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 temp, temp_over; +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83l785ts_data *data = w83l785ts_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83l785ts_data *data = w83l785ts_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); + +/* + * Real code + */ + +static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83l785ts_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct w83l785ts_data *data; + int err = 0; + + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct w83l785ts_data)); + + + /* The common I2C client data is placed right before the + * W83L785TS-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &w83l785ts_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip (actually there is only + * one possible kind of chip for now, W83L785TS-S). A zero kind means + * that the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + if (((w83l785ts_read_value(new_client, + W83L785TS_REG_CONFIG, 0) & 0x80) != 0x00) + || ((w83l785ts_read_value(new_client, + W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) { + dev_dbg(&adapter->dev, + "W83L785TS-S detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u16 man_id; + u8 chip_id; + + man_id = (w83l785ts_read_value(new_client, + W83L785TS_REG_MAN_ID1, 0) << 8) + + w83l785ts_read_value(new_client, + W83L785TS_REG_MAN_ID2, 0); + chip_id = w83l785ts_read_value(new_client, + W83L785TS_REG_CHIP_ID, 0); + + if (man_id == 0x5CA3) { /* Winbond */ + if (chip_id == 0x70) { /* W83L785TS-S */ + kind = w83l785ts; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%04X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + /* We can fill in the remaining client fields. */ + strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Default values in case the first read fails (unlikely). */ + data->temp_over = data->temp = 0; + + /* Tell the I2C layer a new client has arrived. */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* + * Initialize the W83L785TS chip + * Nothing yet, assume it is already started. + */ + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int w83l785ts_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 u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) +{ + int value, i; + + /* Frequent read errors have been reported on Asus boards, so we + * retry on read errors. If it still fails (unlikely), return the + * default value requested by the caller. */ + for (i = 1; i <= MAX_RETRIES; i++) { + value = i2c_smbus_read_byte_data(client, reg); + if (value >= 0) { + dev_dbg(&client->dev, "Read 0x%02x from register " + "0x%02x.\n", value, reg); + return value; + } + dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i); + msleep(i); + } + + dev_err(&client->dev, "Couldn't read value from register 0x%02x. " + "Please report.\n", reg); + return defval; +} + +static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83l785ts_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { + dev_dbg(&client->dev, "Updating w83l785ts data.\n"); + data->temp = w83l785ts_read_value(client, + W83L785TS_REG_TEMP, data->temp); + data->temp_over = w83l785ts_read_value(client, + W83L785TS_REG_TEMP_OVER, data->temp_over); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_w83l785ts_init(void) +{ + return i2c_add_driver(&w83l785ts_driver); +} + +static void __exit sensors_w83l785ts_exit(void) +{ + i2c_del_driver(&w83l785ts_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("W83L785TS-S driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83l785ts_init); +module_exit(sensors_w83l785ts_exit); diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c deleted file mode 100644 index d2c774c32f4..00000000000 --- a/drivers/i2c/chips/adm1021.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); - -/* adm1021 constants specified below */ - -/* The adm1021 registers */ -/* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 -#define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ -/* These use different addresses for reading/writing */ -#define ADM1021_REG_CONFIG_R 0x03 -#define ADM1021_REG_CONFIG_W 0x09 -#define ADM1021_REG_CONV_RATE_R 0x04 -#define ADM1021_REG_CONV_RATE_W 0x0A -/* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 -/* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define ADM1021_REG_ONESHOT 0x0F - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) - -/* Initial values */ - -/* Note: Even though I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actually triggers an alarm instead of -clearing it. Weird, ey? --Phil */ - -/* Each client has this additional data */ -struct adm1021_data { - struct i2c_client client; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 temp_max; /* Register values */ - u8 temp_hyst; - u8 temp_input; - u8 remote_temp_max; - u8 remote_temp_hyst; - u8 remote_temp_input; - u8 alarms; - /* Special values for ADM1023 only */ - u8 remote_temp_prec; - u8 remote_temp_os_prec; - u8 remote_temp_hyst_prec; - u8 remote_temp_offset; - u8 remote_temp_offset_prec; -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1021_init_client(struct i2c_client *client); -static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); -static struct adm1021_data *adm1021_update_device(struct device *dev); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1021_driver = { - .owner = THIS_MODULE, - .name = "adm1021", - .id = I2C_DRIVERID_ADM1021, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1021_attach_adapter, - .detach_client = adm1021_detach_client, -}; - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show(temp_max); -show(temp_hyst); -show(temp_input); -show(remote_temp_max); -show(remote_temp_hyst); -show(remote_temp_input); - -#define show2(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ -} -show2(alarms); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1021_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm1021_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set(temp_max, ADM1021_REG_TOS_W); -set(temp_hyst, ADM1021_REG_THYST_W); -set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); -set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -static int adm1021_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1021_detect); -} - -static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1021_data *data; - int err = 0; - const char *type_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - memset(data, 0, sizeof(struct adm1021_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { - err = -ENODEV; - goto error1; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); - if (i == 0x41) - if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) - kind = adm1023; - else - kind = adm1021; - else if (i == 0x49) - kind = thmc10; - else if (i == 0x23) - kind = gl523sm; - else if ((i == 0x4d) && - (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) - kind = max1617a; - else if (i == 0x54) - kind = mc1066; - /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) - kind = lm84; - else - kind = max1617; - } - - if (kind == max1617) { - type_name = "max1617"; - } else if (kind == max1617a) { - type_name = "max1617a"; - } else if (kind == adm1021) { - type_name = "adm1021"; - } else if (kind == adm1023) { - type_name = "adm1023"; - } else if (kind == thmc10) { - type_name = "thmc10"; - } else if (kind == lm84) { - type_name = "lm84"; - } else if (kind == gl523sm) { - type_name = "gl523sm"; - } else if (kind == mc1066) { - type_name = "mc1066"; - } - - /* 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; - 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 error1; - - /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error1: - kfree(data); -error0: - return err; -} - -static void adm1021_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); -} - -static int adm1021_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; -} - -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (!read_only) - return i2c_smbus_write_byte_data(client, reg, value); - return 0; -} - -static struct adm1021_data *adm1021_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting adm1021 update\n"); - - data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; - if (data->type == adm1023) { - data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1021_init(void) -{ - return i2c_add_driver(&adm1021_driver); -} - -static void __exit sensors_adm1021_exit(void) -{ - i2c_del_driver(&adm1021_driver); -} - -MODULE_AUTHOR ("Frodo Looijaard and " - "Philip Edelbrock "); -MODULE_DESCRIPTION("adm1021 driver"); -MODULE_LICENSE("GPL"); - -module_param(read_only, bool, 0); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sensors_adm1021_init) -module_exit(sensors_adm1021_exit) diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c deleted file mode 100644 index e452d0daf90..00000000000 --- a/drivers/i2c/chips/adm1025.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * adm1025.c - * - * Copyright (C) 2000 Chen-Yuan Wu - * Copyright (C) 2003-2004 Jean Delvare - * - * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6 - * voltages (including its own power source) and up to two temperatures - * (its own plus up to one external one). Voltages are scaled internally - * (which is not the common way) with ratios such that the nominal value - * of each voltage correspond to a register value of 192 (which means a - * resolution of about 0.5% of the nominal value). Temperature values are - * reported with a 1 deg resolution and a 3 deg accuracy. Complete - * datasheet can be obtained from Analog's website at: - * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html - * - * This driver also supports the ADM1025A, which differs from the ADM1025 - * only in that it has "open-drain VID inputs while the ADM1025 has - * on-chip 100k pull-ups on the VID inputs". It doesn't make any - * difference for us. - * - * This driver also supports the NE1619, a sensor chip made by Philips. - * That chip is similar to the ADM1025A, with a few differences. The only - * difference that matters to us is that the NE1619 has only two possible - * addresses while the ADM1025A has a third one. Complete datasheet can be - * obtained from Philips's website at: - * http://www.semiconductors.philips.com/pip/NE1619DS.html - * - * Since the ADM1025 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e. - * NE1619 has two possible addresses: 0x2c and 0x2d. - */ - -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_2(adm1025, ne1619); - -/* - * The ADM1025 registers - */ - -#define ADM1025_REG_MAN_ID 0x3E -#define ADM1025_REG_CHIP_ID 0x3F -#define ADM1025_REG_CONFIG 0x40 -#define ADM1025_REG_STATUS1 0x41 -#define ADM1025_REG_STATUS2 0x42 -#define ADM1025_REG_IN(nr) (0x20 + (nr)) -#define ADM1025_REG_IN_MAX(nr) (0x2B + (nr) * 2) -#define ADM1025_REG_IN_MIN(nr) (0x2C + (nr) * 2) -#define ADM1025_REG_TEMP(nr) (0x26 + (nr)) -#define ADM1025_REG_TEMP_HIGH(nr) (0x37 + (nr) * 2) -#define ADM1025_REG_TEMP_LOW(nr) (0x38 + (nr) * 2) -#define ADM1025_REG_VID 0x47 -#define ADM1025_REG_VID4 0x49 - -/* - * Conversions and various macros - * The ADM1025 uses signed 8-bit values for temperatures. - */ - -static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; - -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ - (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) -#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ - (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) - -/* - * Functions declaration - */ - -static int adm1025_attach_adapter(struct i2c_adapter *adapter); -static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1025_init_client(struct i2c_client *client); -static int adm1025_detach_client(struct i2c_client *client); -static struct adm1025_data *adm1025_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver adm1025_driver = { - .owner = THIS_MODULE, - .name = "adm1025", - .id = I2C_DRIVERID_ADM1025, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1025_attach_adapter, - .detach_client = adm1025_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct adm1025_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - u8 in[6]; /* register value */ - u8 in_max[6]; /* register value */ - u8 in_min[6]; /* register value */ - s8 temp[2]; /* register value */ - s8 temp_min[2]; /* register value */ - s8 temp_max[2]; /* register value */ - u16 alarms; /* register values, combined */ - u8 vid; /* register values, combined */ - u8 vrm; -}; - -/* - * Sysfs stuff - */ - -#define show_in(offset) \ -static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); - -#define show_temp(offset) \ -static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); -show_temp(1); -show_temp(2); - -#define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ - data->in_min[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ - data->in_max[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - show_in##offset##_max, set_in##offset##_max); -set_in(0); -set_in(1); -set_in(2); -set_in(3); -set_in(4); -set_in(5); - -#define set_temp(offset) \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ - data->temp_min[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ - data->temp_max[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); -set_temp(1); -set_temp(2); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ -static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1025_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -/* - * Real code - */ - -static int adm1025_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1025_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm1025_data *data; - int err = 0; - const char *name = ""; - u8 config; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1025_data)); - - /* The common I2C client data is placed right before the - ADM1025-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); - if (kind < 0) { /* detection */ - if ((config & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS2) & 0xBC) != 0x00) { - dev_dbg(&adapter->dev, - "ADM1025 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CHIP_ID); - - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ - kind = adm1025; - } - } else - if (man_id == 0xA1) { /* Philips */ - if (address != 0x2E - && (chip_id & 0xF0) == 0x20) { /* NE1619 */ - kind = ne1619; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == adm1025) { - name = "adm1025"; - } else if (kind == ne1619) { - name = "ne1619"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); - - /* Register sysfs hooks */ - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_alarms); - /* in1_ref is deprecated, remove after 2005-11-11 */ - device_create_file(&new_client->dev, &dev_attr_in1_ref); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - - /* Pin 11 is either in4 (+12V) or VID4 */ - if (!(config & 0x20)) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - } - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void adm1025_init_client(struct i2c_client *client) -{ - u8 reg; - struct adm1025_data *data = i2c_get_clientdata(client); - int i; - - data->vrm = i2c_which_vrm(); - - /* - * Set high limits - * Usually we avoid setting limits on driver init, but it happens - * that the ADM1025 comes with stupid default limits (all registers - * set to 0). In case the chip has not gone through any limit - * setting yet, we better set the high limits to the max so that - * no alarm triggers. - */ - for (i=0; i<6; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_IN_MAX(i), - 0xFF); - } - for (i=0; i<2; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_TEMP_HIGH(i), - 0x7F); - } - - /* - * Start the conversions - */ - reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); - if (!(reg & 0x01)) - i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, - (reg&0x7E)|0x01); -} - -static int adm1025_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 struct adm1025_data *adm1025_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1025_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int i; - - dev_dbg(&client->dev, "Updating data.\n"); - for (i=0; i<6; i++) { - data->in[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN(i)); - data->in_min[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MIN(i)); - data->in_max[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - } - for (i=0; i<2; i++) { - data->temp[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP(i)); - data->temp_min[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_LOW(i)); - data->temp_max[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - } - data->alarms = i2c_smbus_read_byte_data(client, - ADM1025_REG_STATUS1) - | (i2c_smbus_read_byte_data(client, - ADM1025_REG_STATUS2) << 8); - data->vid = (i2c_smbus_read_byte_data(client, - ADM1025_REG_VID) & 0x0f) - | ((i2c_smbus_read_byte_data(client, - ADM1025_REG_VID4) & 0x01) << 4); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1025_init(void) -{ - return i2c_add_driver(&adm1025_driver); -} - -static void __exit sensors_adm1025_exit(void) -{ - i2c_del_driver(&adm1025_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("ADM1025 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1025_init); -module_exit(sensors_adm1025_exit); diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c deleted file mode 100644 index 3c85fe150cd..00000000000 --- a/drivers/i2c/chips/adm1026.c +++ /dev/null @@ -1,1714 +0,0 @@ -/* - adm1026.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2002, 2003 Philip Pokorny - Copyright (C) 2004 Justin Thiessen - - Chip details at: - - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1026); - -static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -module_param_array(gpio_input,int,NULL,0); -MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); -module_param_array(gpio_output,int,NULL,0); -MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " - "outputs"); -module_param_array(gpio_inverted,int,NULL,0); -MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " - "inverted"); -module_param_array(gpio_normal,int,NULL,0); -MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " - "normal/non-inverted"); -module_param_array(gpio_fan,int,NULL,0); -MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); - -/* Many ADM1026 constants specified below */ - -/* The ADM1026 registers */ -#define ADM1026_REG_CONFIG1 0x00 -#define CFG1_MONITOR 0x01 -#define CFG1_INT_ENABLE 0x02 -#define CFG1_INT_CLEAR 0x04 -#define CFG1_AIN8_9 0x08 -#define CFG1_THERM_HOT 0x10 -#define CFG1_DAC_AFC 0x20 -#define CFG1_PWM_AFC 0x40 -#define CFG1_RESET 0x80 -#define ADM1026_REG_CONFIG2 0x01 -/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ -#define ADM1026_REG_CONFIG3 0x07 -#define CFG3_GPIO16_ENABLE 0x01 -#define CFG3_CI_CLEAR 0x02 -#define CFG3_VREF_250 0x04 -#define CFG3_GPIO16_DIR 0x40 -#define CFG3_GPIO16_POL 0x80 -#define ADM1026_REG_E2CONFIG 0x13 -#define E2CFG_READ 0x01 -#define E2CFG_WRITE 0x02 -#define E2CFG_ERASE 0x04 -#define E2CFG_ROM 0x08 -#define E2CFG_CLK_EXT 0x80 - -/* There are 10 general analog inputs and 7 dedicated inputs - * They are: - * 0 - 9 = AIN0 - AIN9 - * 10 = Vbat - * 11 = 3.3V Standby - * 12 = 3.3V Main - * 13 = +5V - * 14 = Vccp (CPU core voltage) - * 15 = +12V - * 16 = -12V - */ -static u16 ADM1026_REG_IN[] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, - 0x2b, 0x2c, 0x2d, 0x2e, 0x2f - }; -static u16 ADM1026_REG_IN_MIN[] = { - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, - 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f - }; -static u16 ADM1026_REG_IN_MAX[] = { - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, - 0x43, 0x44, 0x45, 0x46, 0x47 - }; - -/* Temperatures are: - * 0 - Internal - * 1 - External 1 - * 2 - External 2 - */ -static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 }; -static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; -static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; -static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; -static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; -static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; - -#define ADM1026_REG_FAN(nr) (0x38 + (nr)) -#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) -#define ADM1026_REG_FAN_DIV_0_3 0x02 -#define ADM1026_REG_FAN_DIV_4_7 0x03 - -#define ADM1026_REG_DAC 0x04 -#define ADM1026_REG_PWM 0x05 - -#define ADM1026_REG_GPIO_CFG_0_3 0x08 -#define ADM1026_REG_GPIO_CFG_4_7 0x09 -#define ADM1026_REG_GPIO_CFG_8_11 0x0a -#define ADM1026_REG_GPIO_CFG_12_15 0x0b -/* CFG_16 in REG_CFG3 */ -#define ADM1026_REG_GPIO_STATUS_0_7 0x24 -#define ADM1026_REG_GPIO_STATUS_8_15 0x25 -/* STATUS_16 in REG_STATUS4 */ -#define ADM1026_REG_GPIO_MASK_0_7 0x1c -#define ADM1026_REG_GPIO_MASK_8_15 0x1d -/* MASK_16 in REG_MASK4 */ - -#define ADM1026_REG_COMPANY 0x16 -#define ADM1026_REG_VERSTEP 0x17 -/* These are the recognized values for the above regs */ -#define ADM1026_COMPANY_ANALOG_DEV 0x41 -#define ADM1026_VERSTEP_GENERIC 0x40 -#define ADM1026_VERSTEP_ADM1026 0x44 - -#define ADM1026_REG_MASK1 0x18 -#define ADM1026_REG_MASK2 0x19 -#define ADM1026_REG_MASK3 0x1a -#define ADM1026_REG_MASK4 0x1b - -#define ADM1026_REG_STATUS1 0x20 -#define ADM1026_REG_STATUS2 0x21 -#define ADM1026_REG_STATUS3 0x22 -#define ADM1026_REG_STATUS4 0x23 - -#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6 -#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 -#define ADM1026_PWM_MAX 255 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - * variants. Note that you should be a bit careful with which arguments - * these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors. These are the - * voltages corresponding to 3/4 of full scale (192 or 0xc0) - * NOTE: The -12V input needs an additional factor to account - * for the Vref pullup resistor. - * NEG12_OFFSET = SCALE * Vref / V-192 - Vref - * = 13875 * 2.50 / 1.875 - 2500 - * = 16000 - * - * The values in this table are based on Table II, page 15 of the - * datasheet. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2250, 2250, 2250, 2250, 2250, 2250, - 1875, 1875, 1875, 1875, 3000, 3330, - 3330, 4995, 2250, 12000, 13875 - }; -#define NEG12_OFFSET 16000 -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ - 0,255)) -#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) - -/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses - * and we assume a 2 pulse-per-rev fan tach signal - * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 - */ -#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ - (div)),1,254)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ - (div))) -#define DIV_FROM_REG(val) (1<<(val)) -#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) - -/* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) -#define TEMP_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) -#define OFFSET_FROM_REG(val) ((val) * 1000) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -#define PWM_MIN_TO_REG(val) ((val) & 0xf0) -#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) - -/* Analog output is a voltage, and scaled to millivolts. The datasheet - * indicates that the DAC could be used to drive the fans, but in our - * example board (Arima HDAMA) it isn't connected to the fans at all. - */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) -#define DAC_FROM_REG(val) (((val)*2500)/255) - -/* Typically used with systems using a v9.1 VRM spec ? */ -#define ADM1026_INIT_VRM 91 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define ADM1026_DATA_INTERVAL (1 * HZ) -#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) - -/* We allow for multiple chips in a single system. - * - * For each registered ADM1026, we need to keep state information - * at client->data. The adm1026_data structure is dynamically - * allocated, when a new client structure is allocated. */ - -struct pwm_data { - u8 pwm; - u8 enable; - u8 auto_pwm_min; -}; - -struct adm1026_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[17]; /* Register value */ - u8 in_max[17]; /* Register value */ - u8 in_min[17]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_tmin[3]; /* Register value */ - s8 temp_crit[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u8 fan[8]; /* Register value */ - u8 fan_min[8]; /* Register value */ - u8 fan_div[8]; /* Decoded value */ - struct pwm_data pwm1; /* Pwm control values */ - int vid; /* Decoded value */ - u8 vrm; /* VRM version */ - u8 analog_out; /* Register value (DAC) */ - long alarms; /* Register encoding, combined */ - long alarm_mask; /* Register encoding, combined */ - long gpio; /* Register encoding, combined */ - long gpio_mask; /* Register encoding, combined */ - u8 gpio_config[17]; /* Decoded value */ - u8 config1; /* Register value */ - u8 config2; /* Register value */ - u8 config3; /* Register value */ -}; - -static int adm1026_attach_adapter(struct i2c_adapter *adapter); -static int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind); -static int adm1026_detach_client(struct i2c_client *client); -static int adm1026_read_value(struct i2c_client *client, u8 register); -static int adm1026_write_value(struct i2c_client *client, u8 register, - int value); -static void adm1026_print_gpio(struct i2c_client *client); -static void adm1026_fixup_gpio(struct i2c_client *client); -static struct adm1026_data *adm1026_update_device(struct device *dev); -static void adm1026_init_client(struct i2c_client *client); - - -static struct i2c_driver adm1026_driver = { - .owner = THIS_MODULE, - .name = "adm1026", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1026_attach_adapter, - .detach_client = adm1026_detach_client, -}; - -int adm1026_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) { - return 0; - } - return i2c_detect(adapter, &addr_data, adm1026_detect); -} - -int adm1026_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(client); - return 0; -} - -int adm1026_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - if (reg < 0x80) { - /* "RAM" locations */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff; - } else { - /* EEPROM, do nothing */ - res = 0; - } - return res; -} - -int adm1026_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res; - - if (reg < 0x80) { - /* "RAM" locations */ - res = i2c_smbus_write_byte_data(client, reg, value); - } else { - /* EEPROM, do nothing */ - res = 0; - } - return res; -} - -void adm1026_init_client(struct i2c_client *client) -{ - int value, i; - struct adm1026_data *data = i2c_get_clientdata(client); - - 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, "ADM1026_REG_CONFIG1 is: 0x%02x\n", - data->config1); - if ((data->config1 & CFG1_MONITOR) == 0) { - dev_dbg(&client->dev, "Monitoring not currently " - "enabled.\n"); - } - if (data->config1 & CFG1_INT_ENABLE) { - dev_dbg(&client->dev, "SMBALERT interrupts are " - "enabled.\n"); - } - if (data->config1 & CFG1_AIN8_9) { - dev_dbg(&client->dev, "in8 and in9 enabled. " - "temp3 disabled.\n"); - } else { - dev_dbg(&client->dev, "temp3 enabled. in8 and " - "in9 disabled.\n"); - } - if (data->config1 & CFG1_THERM_HOT) { - 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, "GPIO16 enabled. THERM" - "pin disabled.\n"); - } else { - dev_dbg(&client->dev, "THERM pin enabled. " - "GPIO16 disabled.\n"); - } - if (data->config3 & CFG3_VREF_250) { - dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); - } else { - dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); - } - /* Read and pick apart the existing GPIO configuration */ - value = 0; - for (i = 0;i <= 15;++i) { - if ((i & 0x03) == 0) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4); - } - data->gpio_config[i] = value & 0x03; - value >>= 2; - } - data->gpio_config[16] = (data->config3 >> 6) & 0x03; - - /* ... and then print it */ - adm1026_print_gpio(client); - - /* If the user asks us to reprogram the GPIO config, then - * do it now. - */ - if (gpio_input[0] != -1 || gpio_output[0] != -1 - || gpio_inverted[0] != -1 || gpio_normal[0] != -1 - || gpio_fan[0] != -1) { - adm1026_fixup_gpio(client); - } - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. We DO set the default - * value for pwm1.auto_pwm_min to its maximum - * so that enabling automatic pwm fan control - * without first setting a value for pwm1.auto_pwm_min - * will not result in potentially dangerous fan speed decrease. - */ - data->pwm1.auto_pwm_min=255; - /* Start monitoring */ - 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, "Setting CONFIG to: 0x%02x\n", value); - data->config1 = value; - adm1026_write_value(client, ADM1026_REG_CONFIG1, value); - - /* initialize fan_div[] to hardware defaults */ - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | - (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0;i <= 7;++i) { - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2; - } -} - -void adm1026_print_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - - dev_dbg(&client->dev, "GPIO config is:"); - for (i = 0;i <= 7;++i) { - if (data->config2 & (1 << i)) { - 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, "\tFAN%d\n", i); - } - } - for (i = 8;i <= 15;++i) { - 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%sGP%s16\n", - data->gpio_config[16] & 0x02 ? "" : "!", - data->gpio_config[16] & 0x01 ? "OUT" : "IN"); - } else { - /* GPIO16 is THERM */ - dev_dbg(&client->dev, "\tTHERM\n"); - } -} - -void adm1026_fixup_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - int value; - - /* Make the changes requested. */ - /* We may need to unlock/stop monitoring or soft-reset the - * chip before we can make changes. This hasn't been - * tested much. FIXME - */ - - /* Make outputs */ - for (i = 0;i <= 16;++i) { - if (gpio_output[i] >= 0 && gpio_output[i] <= 16) { - data->gpio_config[gpio_output[i]] |= 0x01; - } - /* if GPIO0-7 is output, it isn't a FAN tach */ - if (gpio_output[i] >= 0 && gpio_output[i] <= 7) { - data->config2 |= 1 << gpio_output[i]; - } - } - - /* Input overrides output */ - for (i = 0;i <= 16;++i) { - if (gpio_input[i] >= 0 && gpio_input[i] <= 16) { - data->gpio_config[gpio_input[i]] &= ~ 0x01; - } - /* if GPIO0-7 is input, it isn't a FAN tach */ - if (gpio_input[i] >= 0 && gpio_input[i] <= 7) { - data->config2 |= 1 << gpio_input[i]; - } - } - - /* Inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { - data->gpio_config[gpio_inverted[i]] &= ~ 0x02; - } - } - - /* Normal overrides inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { - data->gpio_config[gpio_normal[i]] |= 0x02; - } - } - - /* Fan overrides input and output */ - for (i = 0;i <= 7;++i) { - if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) { - data->config2 &= ~(1 << gpio_fan[i]); - } - } - - /* Write new configs to registers */ - adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); - data->config3 = (data->config3 & 0x3f) - | ((data->gpio_config[16] & 0x03) << 6); - adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); - for (i = 15, value = 0;i >= 0;--i) { - value <<= 2; - value |= data->gpio_config[i] & 0x03; - if ((i & 0x03) == 0) { - adm1026_write_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4, - value); - value = 0; - } - } - - /* Print the new config */ - adm1026_print_gpio(client); -} - - -static struct adm1026_data *adm1026_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - long value, alarms, gpio; - - down(&data->update_lock); - if (!data->valid - || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { - /* Things that change quickly */ - 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]); - } - - for (i = 0;i <= 7;++i) { - data->fan[i] = - adm1026_read_value(client, ADM1026_REG_FAN(i)); - } - - for (i = 0;i <= 2;++i) { - /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp[i] = - adm1026_read_value(client, ADM1026_REG_TEMP[i]); - } - - data->pwm1.pwm = adm1026_read_value(client, - ADM1026_REG_PWM); - data->analog_out = adm1026_read_value(client, - ADM1026_REG_DAC); - /* GPIO16 is MSbit of alarms, move it to gpio */ - alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ - alarms &= 0x7f; - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); - data->alarms = alarms; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_STATUS_8_15); - gpio <<= 8; - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_STATUS_0_7); - data->gpio = gpio; - - data->last_reading = jiffies; - }; /* last_reading */ - - if (!data->valid || - time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { - /* Things that don't change often */ - 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]); - data->in_max[i] = adm1026_read_value(client, - ADM1026_REG_IN_MAX[i]); - } - - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) - | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) - << 8); - for (i = 0;i <= 7;++i) { - data->fan_min[i] = adm1026_read_value(client, - ADM1026_REG_FAN_MIN(i)); - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2; - } - - for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's - * complement "conversion" in the assignment - */ - data->temp_min[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_MIN[i]); - data->temp_max[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_MAX[i]); - data->temp_tmin[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_TMIN[i]); - data->temp_crit[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_THERM[i]); - data->temp_offset[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_OFFSET[i]); - } - - /* Read the STATUS/alarm masks */ - alarms = adm1026_read_value(client, ADM1026_REG_MASK4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ - alarms = (alarms & 0x7f) << 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); - data->alarm_mask = alarms; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_MASK_8_15); - gpio <<= 8; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); - data->gpio_mask = gpio; - - /* Read various values from CONFIG1 */ - data->config1 = adm1026_read_value(client, - ADM1026_REG_CONFIG1); - if (data->config1 & CFG1_PWM_AFC) { - data->pwm1.enable = 2; - data->pwm1.auto_pwm_min = - PWM_MIN_FROM_REG(data->pwm1.pwm); - } - /* Read the GPIO config */ - data->config2 = adm1026_read_value(client, - ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, - ADM1026_REG_CONFIG3); - data->gpio_config[16] = (data->config3 >> 6) & 0x03; - - value = 0; - for (i = 0;i <= 15;++i) { - if ((i & 0x03) == 0) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4); - } - data->gpio_config[i] = value & 0x03; - value >>= 2; - } - - data->last_config = jiffies; - }; /* last_config */ - - dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); - data->vid = (data->gpio >> 11) & 0x1f; - data->valid = 1; - up(&data->update_lock); - return data; -} - -static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); -} -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); -} -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = INS_TO_REG(nr, val); - adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); -} -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = INS_TO_REG(nr, val); - adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define in_reg(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \ - NULL, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - - -in_reg(0); -in_reg(1); -in_reg(2); -in_reg(3); -in_reg(4); -in_reg(5); -in_reg(6); -in_reg(7); -in_reg(8); -in_reg(9); -in_reg(10); -in_reg(11); -in_reg(12); -in_reg(13); -in_reg(14); -in_reg(15); - -static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - - NEG12_OFFSET); -} -static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) - - NEG12_OFFSET); -} -static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); - up(&data->update_lock); - return count; -} -static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) - - NEG12_OFFSET); -} -static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); - up(&data->update_lock); - return count; -} - -static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); -static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); -static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); - - - - -/* Now add fan read/write functions */ - -static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], - data->fan_div[nr])); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - data->fan_div[nr])); -} -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]); - adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); - -fan_offset(1); -fan_offset(2); -fan_offset(3); -fan_offset(4); -fan_offset(5); -fan_offset(6); -fan_offset(7); -fan_offset(8); - -/* Adjust fan_min to account for new fan divisor */ -static void fixup_fan_min(struct device *dev, int fan, int old_div) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int new_min; - int new_div = data->fan_div[fan]; - - /* 0 and 0xff are special. Don't adjust them */ - if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { - return; - } - - new_min = data->fan_min[fan] * old_div / new_div; - new_min = SENSORS_LIMIT(new_min, 1, 254); - data->fan_min[fan] = new_min; - adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); -} - -/* Now add fan_div read/write functions */ -static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->fan_div[nr]); -} -static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val,orig_div,new_div,shift; - - val = simple_strtol(buf, NULL, 10); - new_div = DIV_TO_REG(val); - if (new_div == 0) { - return -EINVAL; - } - down(&data->update_lock); - orig_div = data->fan_div[nr]; - data->fan_div[nr] = DIV_FROM_REG(new_div); - - if (nr < 4) { /* 0 <= nr < 4 */ - shift = 2 * nr; - adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, - ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) | - (new_div << shift))); - } else { /* 3 < nr < 8 */ - shift = 2 * (nr - 4); - adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, - ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) | - (new_div << shift))); - } - - if (data->fan_div[nr] != orig_div) { - fixup_fan_min(dev,nr,orig_div); - } - up(&data->update_lock); - return count; -} - -#define fan_offset_div(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -fan_offset_div(1); -fan_offset_div(2); -fan_offset_div(3); -fan_offset_div(4); -fan_offset_div(5); -fan_offset_div(6); -fan_offset_div(7); -fan_offset_div(8); - -/* Temps */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr], - data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr], - data->temp_max[nr]); - up(&data->update_lock); - return count; -} - -#define temp_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ - NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); - - -temp_reg(1); -temp_reg(2); -temp_reg(3); - -static ssize_t show_temp_offset(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); -} -static ssize_t set_temp_offset(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_offset[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr], - data->temp_offset[nr]); - up(&data->update_lock); - return count; -} - -#define temp_offset_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ - show_temp_offset, set_temp_offset, offset - 1); - -temp_offset_reg(1); -temp_offset_reg(2); -temp_offset_reg(3); - -static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG( - ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); -} -static ssize_t show_temp_auto_point2_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + - ADM1026_FAN_CONTROL_TEMP_RANGE)); -} -static ssize_t show_temp_auto_point1_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); -} -static ssize_t set_temp_auto_point1_temp(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_tmin[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr], - data->temp_tmin[nr]); - up(&data->update_lock); - return count; -} - -#define temp_auto_point(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ - show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ - show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ - show_temp_auto_point2_temp, NULL, offset - 1); - -temp_auto_point(1); -temp_auto_point(2); -temp_auto_point(3); - -static ssize_t show_temp_crit_enable(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); -} -static ssize_t set_temp_crit_enable(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - if ((val == 1) || (val==0)) { - down(&data->update_lock); - data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - up(&data->update_lock); - } - return count; -} - -#define temp_crit_enable(offset) \ -static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \ - show_temp_crit_enable, set_temp_crit_enable); - -temp_crit_enable(1); -temp_crit_enable(2); -temp_crit_enable(3); - -static ssize_t show_temp_crit(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); -} -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_crit[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr], - data->temp_crit[nr]); - up(&data->update_lock); - return count; -} - -#define temp_crit_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_crit, set_temp_crit, offset - 1); - -temp_crit_reg(1); -temp_crit_reg(2); -temp_crit_reg(3); - -static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); -} -static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->analog_out = DAC_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, - set_analog_out_reg); - -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); -} -/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ -static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); - -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->vrm); -} -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - - data->vrm = simple_strtol(buf, NULL, 10); - return count; -} - -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); - -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf, "%ld\n", (long) (data->alarms)); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); - -static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->alarm_mask); -} -static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - unsigned long mask; - - down(&data->update_lock); - data->alarm_mask = val & 0x7fffffff; - mask = data->alarm_mask - | (data->gpio_mask & 0x10000 ? 0x80000000 : 0); - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK2, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK3, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK4, - mask & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, - set_alarm_mask); - - -static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio); -} -static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - long gpio; - - down(&data->update_lock); - data->gpio = val & 0x1ffff; - gpio = data->gpio; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); - gpio >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff); - gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); - - -static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio_mask); -} -static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - long mask; - - down(&data->update_lock); - data->gpio_mask = val & 0x1ffff; - mask = data->gpio_mask; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff); - mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); - -static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); -} -static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - - if (data->pwm1.enable == 1) { - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm1.pwm = PWM_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); - up(&data->update_lock); - } - return count; -} -static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); -} -static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255); - if (data->pwm1.enable == 2) { /* apply immediately */ - data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); - } - up(&data->update_lock); - return count; -} -static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%d\n", ADM1026_PWM_MAX); -} -static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.enable); -} -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int old_enable; - - if ((val >= 0) && (val < 3)) { - down(&data->update_lock); - old_enable = data->pwm1.enable; - data->pwm1.enable = val; - data->config1 = (data->config1 & ~CFG1_PWM_AFC) - | ((val == 2) ? CFG1_PWM_AFC : 0); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ - data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } else if (!((old_enable == 1) && (val == 1))) { - /* set pwm to safe value */ - data->pwm1.pwm = 255; - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } - up(&data->update_lock); - } - return count; -} - -/* enable PWM fan control */ -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); - -static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); - -int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int company, verstep; - struct i2c_client *new_client; - struct adm1026_data *data; - int err = 0; - const char *type_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto exit; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1026_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - memset(data, 0, sizeof(struct adm1026_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1026_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); - verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); - - dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep); - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { - dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x " - "...\n", i2c_adapter_id(adapter), address); - if (company == ADM1026_COMPANY_ANALOG_DEV - && verstep == ADM1026_VERSTEP_ADM1026) { - kind = adm1026; - } else if (company == ADM1026_COMPANY_ANALOG_DEV - && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { - dev_err(&adapter->dev, ": Unrecognized stepping " - "0x%02x. Defaulting to ADM1026.\n", verstep); - kind = adm1026; - } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { - dev_err(&adapter->dev, ": Found version/stepping " - "0x%02x. Assuming generic ADM1026.\n", - verstep); - kind = any_chip; - } else { - dev_dbg(&new_client->dev, ": Autodetection " - "failed\n"); - /* Not an ADM1026 ... */ - if (kind == 0) { /* User used force=x,y */ - dev_err(&adapter->dev, "Generic ADM1026 not " - "found at %d,0x%02x. Try " - "force_adm1026.\n", - i2c_adapter_id(adapter), address); - } - err = 0; - goto exitfree; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "adm1026"; - break; - case adm1026 : - type_name = "adm1026"; - break; - default : - dev_err(&adapter->dev, ": Internal error, invalid " - "kind (%d)!", kind); - err = -EFAULT; - goto exitfree; - } - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); - - /* Fill in the remaining client fields */ - data->type = kind; - 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 exitfree; - - /* Set the VRM version */ - data->vrm = i2c_which_vrm(); - - /* Initialize the ADM1026 chip */ - adm1026_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); - /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ - device_create_file(&new_client->dev, &dev_attr_vid); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_alarm_mask); - device_create_file(&new_client->dev, &dev_attr_gpio); - device_create_file(&new_client->dev, &dev_attr_gpio_mask); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_analog_out); - return 0; - - /* Error out and cleanup code */ -exitfree: - kfree(new_client); -exit: - return err; -} -static int __init sm_adm1026_init(void) -{ - return i2c_add_driver(&adm1026_driver); -} - -static void __exit sm_adm1026_exit(void) -{ - i2c_del_driver(&adm1026_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny , " - "Justin Thiessen "); -MODULE_DESCRIPTION("ADM1026 driver"); - -module_init(sm_adm1026_init); -module_exit(sm_adm1026_exit); diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c deleted file mode 100644 index 9168e983ca1..00000000000 --- a/drivers/i2c/chips/adm1031.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - adm1031.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Based on lm75.c and lm85.c - Supports adm1030 / adm1031 - Copyright (C) 2004 Alexandre d'Alton - Reworked by Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - -/* Following macros takes channel parameter starting from 0 to 2 */ -#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) -#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) -#define ADM1031_REG_PWM (0x22) -#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) - -#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) -#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) -#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) - -#define ADM1031_REG_TEMP(nr) (0xa + (nr)) -#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) - -#define ADM1031_REG_STATUS(nr) (0x2 + (nr)) - -#define ADM1031_REG_CONF1 0x0 -#define ADM1031_REG_CONF2 0x1 -#define ADM1031_REG_EXT_TEMP 0x6 - -#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ -#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ -#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ - -#define ADM1031_CONF2_PWM1_ENABLE 0x01 -#define ADM1031_CONF2_PWM2_ENABLE 0x02 -#define ADM1031_CONF2_TACH1_ENABLE 0x04 -#define ADM1031_CONF2_TACH2_ENABLE 0x08 -#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1030, adm1031); - -typedef u8 auto_chan_table_t[8][2]; - -/* Each client has this additional data */ -struct adm1031_data { - struct i2c_client client; - struct semaphore update_lock; - int chip_type; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - /* The chan_select_table contains the possible configurations for - * auto fan control. - */ - auto_chan_table_t *chan_select_table; - u16 alarm; - u8 conf1; - u8 conf2; - u8 fan[2]; - u8 fan_div[2]; - u8 fan_min[2]; - u8 pwm[2]; - u8 old_pwm[2]; - s8 temp[3]; - u8 ext_temp[3]; - u8 auto_temp[3]; - u8 auto_temp_min[3]; - u8 auto_temp_off[3]; - u8 auto_temp_max[3]; - s8 temp_min[3]; - s8 temp_max[3]; - s8 temp_crit[3]; -}; - -static int adm1031_attach_adapter(struct i2c_adapter *adapter); -static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1031_init_client(struct i2c_client *client); -static int adm1031_detach_client(struct i2c_client *client); -static struct adm1031_data *adm1031_update_device(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1031_driver = { - .owner = THIS_MODULE, - .name = "adm1031", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1031_attach_adapter, - .detach_client = adm1031_detach_client, -}; - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int -adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - - -#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ - ((val + 500) / 1000))) - -#define TEMP_FROM_REG(val) ((val) * 1000) - -#define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) - -#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) - -static int FAN_TO_REG(int reg, int div) -{ - int tmp; - tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); - return tmp > 255 ? 255 : tmp; -} - -#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) -#define PWM_FROM_REG(val) ((val) << 4) - -#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) -#define FAN_CHAN_TO_REG(val, reg) \ - (((reg) & 0x1F) | (((val) << 5) & 0xe0)) - -#define AUTO_TEMP_MIN_TO_REG(val, reg) \ - ((((val)/500) & 0xf8)|((reg) & 0x7)) -#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) -#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) - -#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) - -#define AUTO_TEMP_OFF_FROM_REG(reg) \ - (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) - -#define AUTO_TEMP_MAX_FROM_REG(reg) \ - (AUTO_TEMP_RANGE_FROM_REG(reg) + \ - AUTO_TEMP_MIN_FROM_REG(reg)) - -static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) -{ - int ret; - int range = val - AUTO_TEMP_MIN_FROM_REG(reg); - - range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm); - ret = ((reg & 0xf8) | - (range < 10000 ? 0 : - range < 20000 ? 1 : - range < 40000 ? 2 : range < 80000 ? 3 : 4)); - return ret; -} - -/* FAN auto control */ -#define GET_FAN_AUTO_BITFIELD(data, idx) \ - (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] - -/* The tables below contains the possible values for the auto fan - * control bitfields. the index in the table is the register value. - * MSb is the auto fan control enable bit, so the four first entries - * in the table disables auto fan control when both bitfields are zero. - */ -static auto_chan_table_t auto_channel_select_table_adm1031 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b010 */ , 4 /*0b100 */ }, - {2 /*0b010 */ , 2 /*0b010 */ }, - {4 /*0b100 */ , 4 /*0b100 */ }, - {7 /*0b111 */ , 7 /*0b111 */ }, -}; - -static auto_chan_table_t auto_channel_select_table_adm1030 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b10 */ , 0}, - {0xff /*invalid */ , 0}, - {0xff /*invalid */ , 0}, - {3 /*0b11 */ , 0}, -}; - -/* That function checks if a bitfield is valid and returns the other bitfield - * nearest match if no exact match where found. - */ -static int -get_fan_auto_nearest(struct adm1031_data *data, - int chan, u8 val, u8 reg, u8 * new_reg) -{ - int i; - int first_match = -1, exact_match = -1; - u8 other_reg_val = - (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; - - if (val == 0) { - *new_reg = 0; - return 0; - } - - for (i = 0; i < 8; i++) { - if ((val == (*data->chan_select_table)[i][chan]) && - ((*data->chan_select_table)[i][chan ? 0 : 1] == - other_reg_val)) { - /* We found an exact match */ - exact_match = i; - break; - } else if (val == (*data->chan_select_table)[i][chan] && - first_match == -1) { - /* Save the first match in case of an exact match has not been - * found - */ - first_match = i; - } - } - - if (exact_match >= 0) { - *new_reg = exact_match; - } else if (first_match >= 0) { - *new_reg = first_match; - } else { - return -EINVAL; - } - return 0; -} - -static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); -} - -static ssize_t -set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - u8 reg; - int ret; - u8 old_fan_mode; - - old_fan_mode = data->conf1; - - down(&data->update_lock); - - if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { - up(&data->update_lock); - return ret; - } - if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ - (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { - if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ - /* Switch to Auto Fan Mode - * Save PWM registers - * Set PWM registers to 33% Both */ - data->old_pwm[0] = data->pwm[0]; - data->old_pwm[1] = data->pwm[1]; - adm1031_write_value(client, ADM1031_REG_PWM, 0x55); - } else { - /* Switch to Manual Mode */ - data->pwm[0] = data->old_pwm[0]; - data->pwm[1] = data->old_pwm[1]; - /* Restore PWM registers */ - adm1031_write_value(client, ADM1031_REG_PWM, - data->pwm[0] | (data->pwm[1] << 4)); - } - } - data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); - adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); - up(&data->update_lock); - return count; -} - -#define fan_auto_channel_offset(offset) \ -static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_auto_channel(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_auto_channel(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ - show_fan_auto_channel_##offset, \ - set_fan_auto_channel_##offset) - -fan_auto_channel_offset(1); -fan_auto_channel_offset(2); - -/* Auto Temps */ -static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); -} -static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); -} -static ssize_t -set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); - adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), - data->auto_temp[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); -} -static ssize_t -set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); - adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), - data->temp_max[nr]); - up(&data->update_lock); - return count; -} - -#define auto_temp_reg(offset) \ -static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ - show_auto_temp_##offset##_off, NULL); \ -static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ -static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) - -auto_temp_reg(1); -auto_temp_reg(2); -auto_temp_reg(3); - -/* pwm */ -static ssize_t show_pwm(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); -} -static ssize_t -set_pwm(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int reg; - - down(&data->update_lock); - if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && - (((val>>4) & 0xf) != 5)) { - /* In automatic mode, the only PWM accepted is 33% */ - up(&data->update_lock); - return -EINVAL; - } - data->pwm[nr] = PWM_TO_REG(val); - reg = adm1031_read_value(client, ADM1031_REG_PWM); - adm1031_write_value(client, ADM1031_REG_PWM, - nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) - : (data->pwm[nr] & 0xf) | (reg & 0xf0)); - up(&data->update_lock); - return count; -} - -#define pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) - -pwm_reg(1); -pwm_reg(2); - -/* Fans */ - -/* - * That function checks the cases where the fan reading is not - * relevant. It is used to provide 0 as fan reading when the fan is - * not supposed to run - */ -static int trust_fan_readings(struct adm1031_data *data, int chan) -{ - int res = 0; - - if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { - switch (data->conf1 & 0x60) { - case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ - res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); - break; - case 0x20: /* remote temp1 controls both fans */ - res = - data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); - break; - case 0x40: /* remote temp2 controls both fans */ - res = - data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); - break; - case 0x60: /* max controls both fans */ - res = - data->temp[0] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) - || data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) - || (data->chip_type == adm1031 - && data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); - break; - } - } else { - res = data->pwm[chan] > 0; - } - return res; -} - - -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - int value; - - value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; - return sprintf(buf, "%d\n", value); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t -set_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - if (val) { - data->fan_min[nr] = - FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); - } else { - data->fan_min[nr] = 0xff; - } - adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_fan_div(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - u8 tmp; - int old_div; - int new_min; - - tmp = val == 8 ? 0xc0 : - val == 4 ? 0x80 : - val == 2 ? 0x40 : - val == 1 ? 0x00 : - 0xff; - if (tmp == 0xff) - return -EINVAL; - - down(&data->update_lock); - old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); - data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); - new_min = data->fan_min[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); - data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; - data->fan[nr] = data->fan[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); - - adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), - data->fan_div[nr]); - adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); \ -static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) - -fan_offset(1); -fan_offset(2); - - -/* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - int ext; - ext = nr == 0 ? - ((data->ext_temp[nr] >> 6) & 0x3) * 2 : - (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); - return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); -} -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); -} -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); -} -static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); -} -static ssize_t -set_temp_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), - data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_temp_max(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), - data->temp_max[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_crit[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), - data->temp_crit[nr]); - up(&data->update_lock); - return count; -} - -#define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_crit, set_temp_##offset##_crit) - -temp_reg(1); -temp_reg(2); -temp_reg(3); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", data->alarm); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -static int adm1031_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1031_detect); -} - -/* This function is called by i2c_detect */ -static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm1031_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1031_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1031_driver; - new_client->flags = 0; - - if (kind < 0) { - int id, co; - id = i2c_smbus_read_byte_data(new_client, 0x3d); - co = i2c_smbus_read_byte_data(new_client, 0x3e); - - if (!((id == 0x31 || id == 0x30) && co == 0x41)) - goto exit_free; - kind = (id == 0x30) ? adm1030 : adm1031; - } - - if (kind <= 0) - kind = adm1031; - - /* Given the detected chip type, set the chip name and the - * auto fan control helper table. */ - if (kind == adm1030) { - name = "adm1030"; - data->chan_select_table = &auto_channel_select_table_adm1030; - } else if (kind == adm1031) { - name = "adm1031"; - data->chan_select_table = &auto_channel_select_table_adm1031; - } - data->chip_type = kind; - - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the ADM1031 chip */ - adm1031_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - - device_create_file(&new_client->dev, &dev_attr_auto_temp1_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_max); - - device_create_file(&new_client->dev, &dev_attr_auto_temp2_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_max); - - device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm); - - device_create_file(&new_client->dev, &dev_attr_alarms); - - if (kind == adm1031) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, - &dev_attr_auto_fan2_channel); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_max); - device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm); - } - - return 0; - -exit_free: - kfree(new_client); -exit: - return err; -} - -static int adm1031_detach_client(struct i2c_client *client) -{ - int ret; - if ((ret = i2c_detach_client(client)) != 0) { - return ret; - } - kfree(client); - return 0; -} - -static void adm1031_init_client(struct i2c_client *client) -{ - unsigned int read_val; - unsigned int mask; - struct adm1031_data *data = i2c_get_clientdata(client); - - mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); - if (data->chip_type == adm1031) { - mask |= (ADM1031_CONF2_PWM2_ENABLE | - ADM1031_CONF2_TACH2_ENABLE); - } - /* Initialize the ADM1031 chip (enables fan speed reading ) */ - read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); - } - - read_val = adm1031_read_value(client, ADM1031_REG_CONF1); - if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); - } - -} - -static struct adm1031_data *adm1031_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int chan; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting adm1031 update\n"); - for (chan = 0; - chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { - u8 oldh, newh; - - oldh = - adm1031_read_value(client, ADM1031_REG_TEMP(chan)); - data->ext_temp[chan] = - adm1031_read_value(client, ADM1031_REG_EXT_TEMP); - newh = - adm1031_read_value(client, ADM1031_REG_TEMP(chan)); - if (newh != oldh) { - data->ext_temp[chan] = - adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); -#ifdef DEBUG - oldh = - adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, - "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp[chan] = newh; - - data->temp_min[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_MIN(chan)); - data->temp_max[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_MAX(chan)); - data->temp_crit[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_CRIT(chan)); - data->auto_temp[chan] = - adm1031_read_value(client, - ADM1031_REG_AUTO_TEMP(chan)); - - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); - - data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { - data->alarm &= 0xc0ff; - } - - for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { - data->fan_div[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); - data->fan_min[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); - data->fan[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); - data->pwm[chan] = - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> - (4*chan)); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1031_init(void) -{ - return i2c_add_driver(&adm1031_driver); -} - -static void __exit sensors_adm1031_exit(void) -{ - i2c_del_driver(&adm1031_driver); -} - -MODULE_AUTHOR("Alexandre d'Alton "); -MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1031_init); -module_exit(sensors_adm1031_exit); diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c deleted file mode 100644 index 5c68e9c311a..00000000000 --- a/drivers/i2c/chips/adm9240.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * adm9240.c Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * - * Copyright (C) 1999 Frodo Looijaard - * Philip Edelbrock - * Copyright (C) 2003 Michiel Rook - * Copyright (C) 2005 Grant Coady with valuable - * guidance from Jean Delvare - * - * Driver supports Analog Devices ADM9240 - * Dallas Semiconductor DS1780 - * National Semiconductor LM81 - * - * ADM9240 is the reference, DS1780 and LM81 are register compatibles - * - * Voltage Six inputs are scaled by chip, VID also reported - * Temperature Chip temperature to 0.5'C, maximum and max_hysteris - * Fans 2 fans, low speed alarm, automatic fan clock divider - * Alarms 16-bit map of active alarms - * Analog Out 0..1250 mV output - * - * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' - * - * Test hardware: Intel SE440BX-2 desktop motherboard --Grant - * - * LM81 extended temp reading not implemented - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, - I2C_CLIENT_END }; - -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(adm9240, ds1780, lm81); - -/* ADM9240 registers */ -#define ADM9240_REG_MAN_ID 0x3e -#define ADM9240_REG_DIE_REV 0x3f -#define ADM9240_REG_CONFIG 0x40 - -#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ -#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ -#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) -#define ADM9240_REG_INT(nr) (0x41 + (nr)) -#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) -#define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_TEMP_HIGH 0x39 -#define ADM9240_REG_TEMP_HYST 0x3a -#define ADM9240_REG_ANALOG_OUT 0x19 -#define ADM9240_REG_CHASSIS_CLEAR 0x46 -#define ADM9240_REG_VID_FAN_DIV 0x47 -#define ADM9240_REG_I2C_ADDR 0x48 -#define ADM9240_REG_VID4 0x49 -#define ADM9240_REG_TEMP_CONF 0x4b - -/* generalised scaling with integer rounding */ -static inline int SCALE(long val, int mul, int div) -{ - if (val < 0) - return (val * mul - div / 2) / div; - else - return (val * mul + div / 2) / div; -} - -/* adm9240 internally scales voltage measurements */ -static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; - -static inline unsigned int IN_FROM_REG(u8 reg, int n) -{ - return SCALE(reg, nom_mv[n], 192); -} - -static inline u8 IN_TO_REG(unsigned long val, int n) -{ - return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); -} - -/* temperature range: -40..125, 127 disables temperature alarm */ -static inline s8 TEMP_TO_REG(long val) -{ - return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); -} - -/* two fans, each with low fan speed limit */ -static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) -{ - if (!reg) /* error */ - return -1; - - if (reg == 255) - return 0; - - return SCALE(1350000, 1, reg * div); -} - -/* analog out 0..1250mV */ -static inline u8 AOUT_TO_REG(unsigned long val) -{ - return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); -} - -static inline unsigned int AOUT_FROM_REG(u8 reg) -{ - return SCALE(reg, 1250, 255); -} - -static int adm9240_attach_adapter(struct i2c_adapter *adapter); -static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm9240_init_client(struct i2c_client *client); -static int adm9240_detach_client(struct i2c_client *client); -static struct adm9240_data *adm9240_update_device(struct device *dev); - -/* driver data */ -static struct i2c_driver adm9240_driver = { - .owner = THIS_MODULE, - .name = "adm9240", - .id = I2C_DRIVERID_ADM9240, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm9240_attach_adapter, - .detach_client = adm9240_detach_client, -}; - -/* per client data */ -struct adm9240_data { - enum chips type; - struct i2c_client client; - struct semaphore update_lock; - char valid; - unsigned long last_updated_measure; - unsigned long last_updated_config; - - u8 in[6]; /* ro in0_input */ - u8 in_max[6]; /* rw in0_max */ - u8 in_min[6]; /* rw in0_min */ - u8 fan[2]; /* ro fan1_input */ - u8 fan_min[2]; /* rw fan1_min */ - u8 fan_div[2]; /* rw fan1_div, read-only accessor */ - s16 temp; /* ro temp1_input, 9-bit sign-extended */ - s8 temp_high; /* rw temp1_max */ - s8 temp_hyst; /* rw temp1_max_hyst */ - u16 alarms; /* ro alarms */ - u8 aout; /* rw aout_output */ - u8 vid; /* ro vid */ - u8 vrm; /* -- vrm set on startup, no accessor */ -}; - -/* i2c byte read/write interface */ -static int adm9240_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/*** sysfs accessors ***/ - -/* temperature */ -#define show_temp(value, scale) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct adm9240_data *data = adm9240_update_device(dev); \ - return sprintf(buf, "%d\n", data->value * scale); \ -} -show_temp(temp_high, 1000); -show_temp(temp_hyst, 1000); -show_temp(temp, 500); /* 0.5'C per bit */ - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm9240_data *data = adm9240_update_device(dev); \ - long temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm9240_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp(temp_high, ADM9240_REG_TEMP_HIGH); -set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_high, set_temp_high); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, - show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); - -/* voltage */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t show_in##offset(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static ssize_t show_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t \ -set_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t \ -set_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); - -/* fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - 1 << data->fan_div[nr])); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - 1 << data->fan_div[nr])); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); -} - -/* write new fan div, callers must hold data->update_lock */ -static void adm9240_write_fan_div(struct i2c_client *client, int nr, - u8 fan_div) -{ - u8 reg, old, shift = (nr + 2) * 2; - - reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); - old = (reg >> shift) & 3; - reg &= ~(3 << shift); - reg |= (fan_div << shift); - adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); - dev_dbg(&client->dev, "fan%d clock divider changed from %u " - "to %u\n", nr + 1, 1 << old, 1 << fan_div); -} - -/* - * set fan speed low limit: - * - * - value is zero: disable fan speed low limit alarm - * - * - value is below fan speed measurement range: enable fan speed low - * limit alarm to be asserted while fan speed too slow to measure - * - * - otherwise: select fan clock divider to suit fan speed low limit, - * measurement code may adjust registers to ensure fan speed reading - */ -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - u8 new_div; - - down(&data->update_lock); - - if (!val) { - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; - - dev_dbg(&client->dev, "fan%u low limit set disabled\n", - nr + 1); - - } else if (val < 1350000 / (8 * 254)) { - new_div = 3; - data->fan_min[nr] = 254; - - dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", - nr + 1, FAN_FROM_REG(254, 1 << new_div)); - - } else { - unsigned int new_min = 1350000 / val; - - new_div = 0; - while (new_min > 192 && new_div < 3) { - new_div++; - new_min /= 2; - } - if (!new_min) /* keep > 0 */ - new_min++; - - data->fan_min[nr] = new_min; - - dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", - nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); - } - - if (new_div != data->fan_div[nr]) { - data->fan_div[nr] = new_div; - adm9240_write_fan_div(client, nr, new_div); - } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), - data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ -return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan_##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); - -/* alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* vid */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -/* analog output */ -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); -} - -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->aout = AOUT_TO_REG(val); - adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); - up(&data->update_lock); - return count; -} -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); - -/* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - unsigned long val = simple_strtol(buf, NULL, 10); - - if (val == 1) { - adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); - dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); - } - return count; -} -static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); - - -/*** sensor chip detect and driver install ***/ - -static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm9240_data *data; - int err = 0; - const char *name = ""; - u8 man_id, die_rev; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm9240_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm9240_driver; - new_client->flags = 0; - - if (kind == 0) { - kind = adm9240; - } - - if (kind < 0) { - - /* verify chip: reg address should match i2c address */ - if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) - != address) { - dev_err(&adapter->dev, "detect fail: address match, " - "0x%02x\n", address); - goto exit_free; - } - - /* check known chip manufacturer */ - man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); - - if (man_id == 0x23) { - kind = adm9240; - } else if (man_id == 0xda) { - kind = ds1780; - } else if (man_id == 0x01) { - kind = lm81; - } else { - dev_err(&adapter->dev, "detect fail: unknown manuf, " - "0x%02x\n", man_id); - goto exit_free; - } - - /* successful detect, print chip info */ - die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); - dev_info(&adapter->dev, "found %s revision %u\n", - man_id == 0x23 ? "ADM9240" : - man_id == 0xda ? "DS1780" : "LM81", die_rev); - } - - /* either forced or detected chip kind */ - if (kind == adm9240) { - name = "adm9240"; - } else if (kind == ds1780) { - name = "ds1780"; - } else if (kind == lm81) { - name = "lm81"; - } - - /* fill in the remaining client fields and attach */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->type = kind; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - adm9240_init_client(new_client); - - /* populate sysfs filesystem */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); - device_create_file(&new_client->dev, &dev_attr_chassis_clear); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - return 0; -exit_free: - kfree(new_client); -exit: - return err; -} - -static int adm9240_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm9240_detect); -} - -static int adm9240_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 void adm9240_init_client(struct i2c_client *client) -{ - struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); - u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; - - data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ - - dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, - data->vrm % 10); - - if (conf & 1) { /* measurement cycle running: report state */ - - dev_info(&client->dev, "status: config 0x%02x mode %u\n", - conf, mode); - - } else { /* cold start: open limits before starting chip */ - int i; - - for (i = 0; i < 6; i++) - { - adm9240_write_value(client, - ADM9240_REG_IN_MIN(i), 0); - adm9240_write_value(client, - ADM9240_REG_IN_MAX(i), 255); - } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); - adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); - adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); - adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); - - /* start measurement cycle */ - adm9240_write_value(client, ADM9240_REG_CONFIG, 1); - - dev_info(&client->dev, "cold start: config was 0x%02x " - "mode %u\n", conf, mode); - } -} - -static struct adm9240_data *adm9240_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - /* minimum measurement cycle: 1.75 seconds */ - if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) - || !data->valid) { - - for (i = 0; i < 6; i++) /* read voltages */ - { - data->in[i] = adm9240_read_value(client, - ADM9240_REG_IN(i)); - } - data->alarms = adm9240_read_value(client, - ADM9240_REG_INT(0)) | - adm9240_read_value(client, - ADM9240_REG_INT(1)) << 8; - - /* read temperature: assume temperature changes less than - * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = ((adm9240_read_value(client, - ADM9240_REG_TEMP) << 8) | - adm9240_read_value(client, - ADM9240_REG_TEMP_CONF)) / 128; - - for (i = 0; i < 2; i++) /* read fans */ - { - data->fan[i] = adm9240_read_value(client, - ADM9240_REG_FAN(i)); - - /* adjust fan clock divider on overflow */ - if (data->valid && data->fan[i] == 255 && - data->fan_div[i] < 3) { - - adm9240_write_fan_div(client, i, - ++data->fan_div[i]); - - /* adjust fan_min if active, but not to 0 */ - if (data->fan_min[i] < 255 && - data->fan_min[i] >= 2) - data->fan_min[i] /= 2; - } - } - data->last_updated_measure = jiffies; - } - - /* minimum config reading cycle: 300 seconds */ - if (time_after(jiffies, data->last_updated_config + (HZ * 300)) - || !data->valid) { - - for (i = 0; i < 6; i++) - { - data->in_min[i] = adm9240_read_value(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = adm9240_read_value(client, - ADM9240_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) - { - data->fan_min[i] = adm9240_read_value(client, - ADM9240_REG_FAN_MIN(i)); - } - data->temp_high = adm9240_read_value(client, - ADM9240_REG_TEMP_HIGH); - data->temp_hyst = adm9240_read_value(client, - ADM9240_REG_TEMP_HYST); - - /* read fan divs and 5-bit VID */ - i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 3; - data->fan_div[1] = (i >> 6) & 3; - data->vid = i & 0x0f; - data->vid |= (adm9240_read_value(client, - ADM9240_REG_VID4) & 1) << 4; - /* read analog out */ - data->aout = adm9240_read_value(client, - ADM9240_REG_ANALOG_OUT); - - data->last_updated_config = jiffies; - data->valid = 1; - } - up(&data->update_lock); - return data; -} - -static int __init sensors_adm9240_init(void) -{ - return i2c_add_driver(&adm9240_driver); -} - -static void __exit sensors_adm9240_exit(void) -{ - i2c_del_driver(&adm9240_driver); -} - -MODULE_AUTHOR("Michiel Rook , " - "Grant Coady and others"); -MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm9240_init); -module_exit(sensors_adm9240_exit); - diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c deleted file mode 100644 index 70d996d6fe0..00000000000 --- a/drivers/i2c/chips/asb100.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - asb100.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (C) 2004 Mark M. Hoffman - - (derived from w83781d.c) - - Copyright (C) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , and - Mark Studebaker - - 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. -*/ - -/* - This driver supports the hardware sensor chips: Asus ASB100 and - ASB100-A "BACH". - - ASB100-A supports pwm1, while plain ASB100 does not. There is no known - way for the driver to tell which one is there. - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - asb100 7 3 1 4 0x31 0x0694 yes no -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* - HISTORY: - 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6 -*/ -#define ASB100_VERSION "1.0.0" - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(asb100); -I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -/* Voltage IN registers 0-6 */ -#define ASB100_REG_IN(nr) (0x20 + (nr)) -#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) -#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) - -/* FAN IN registers 1-3 */ -#define ASB100_REG_FAN(nr) (0x28 + (nr)) -#define ASB100_REG_FAN_MIN(nr) (0x3b + (nr)) - -/* TEMPERATURE registers 1-4 */ -static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; -static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; -static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; - -#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) -#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) -#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) - -#define ASB100_REG_TEMP2_CONFIG 0x0152 -#define ASB100_REG_TEMP3_CONFIG 0x0252 - - -#define ASB100_REG_CONFIG 0x40 -#define ASB100_REG_ALARM1 0x41 -#define ASB100_REG_ALARM2 0x42 -#define ASB100_REG_SMIM1 0x43 -#define ASB100_REG_SMIM2 0x44 -#define ASB100_REG_VID_FANDIV 0x47 -#define ASB100_REG_I2C_ADDR 0x48 -#define ASB100_REG_CHIPID 0x49 -#define ASB100_REG_I2C_SUBADDR 0x4a -#define ASB100_REG_PIN 0x4b -#define ASB100_REG_IRQ 0x4c -#define ASB100_REG_BANK 0x4e -#define ASB100_REG_CHIPMAN 0x4f - -#define ASB100_REG_WCHIPID 0x58 - -/* bit 7 -> enable, bits 0-3 -> duty cycle */ -#define ASB100_REG_PWM1 0x59 - -/* CONVERSIONS - Rounding and limit checking is only done on the TO_REG variants. */ - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_IN_MIN ( 0) -#define ASB100_IN_MAX (4080) - -/* IN: 1/1000 V (0V to 4.08V) - REG: 16mV/bit */ -static u8 IN_TO_REG(unsigned val) -{ - unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); - return (nval + 8) / 16; -} - -static unsigned IN_FROM_REG(u8 reg) -{ - return reg * 16; -} - -static u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == -1) - return 0; - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_TEMP_MIN (-128000) -#define ASB100_TEMP_MAX ( 127000) - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); - return (u8)(ntemp / 1000); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 1000; -} - -/* PWM: 0 - 255 per sensors documentation - REG: (6.25% duty cycle per bit) */ -static u8 ASB100_PWM_TO_REG(int pwm) -{ - pwm = SENSORS_LIMIT(pwm, 0, 255); - return (u8)(pwm / 16); -} - -static int ASB100_PWM_FROM_REG(u8 reg) -{ - return reg * 16; -} - -#define DIV_FROM_REG(val) (1 << (val)) - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static u8 DIV_TO_REG(long val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, at the same time the client itself is allocated. */ -struct asb100_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* array of 2 pointers to subclients */ - struct i2c_client *lm75[2]; - - char valid; /* !=0 if following fields are valid */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u16 temp[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ - u8 fan_div[3]; /* Register encoding, right justified */ - u8 pwm; /* Register encoding */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 vrm; -}; - -static int asb100_read_value(struct i2c_client *client, u16 reg); -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); - -static int asb100_attach_adapter(struct i2c_adapter *adapter); -static int asb100_detect(struct i2c_adapter *adapter, int address, int kind); -static int asb100_detach_client(struct i2c_client *client); -static struct asb100_data *asb100_update_device(struct device *dev); -static void asb100_init_client(struct i2c_client *client); - -static struct i2c_driver asb100_driver = { - .owner = THIS_MODULE, - .name = "asb100", - .id = I2C_DRIVERID_ASB100, - .flags = I2C_DF_NOTIFY, - .attach_adapter = asb100_attach_adapter, - .detach_client = asb100_detach_client, -}; - -/* 7 Voltages */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct asb100_data *data = asb100_update_device(dev); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ -} - -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define set_in_reg(REG, reg) \ -static ssize_t set_in_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - asb100_write_value(client, ASB100_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} - -set_in_reg(MIN, min) -set_in_reg(MAX, max) - -#define sysfs_in(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -sysfs_in(0); -sysfs_in(1); -sysfs_in(2); -sysfs_in(3); -sysfs_in(4); -sysfs_in(5); -sysfs_in(6); - -#define device_create_file_in(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ - device_create_file(&client->dev, &dev_attr_in##offset##_min); \ - device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); - int reg; - - down(&data->update_lock); - - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = DIV_TO_REG(val); - - switch(nr) { - case 0: /* fan 1 */ - reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); - reg = (reg & 0xcf) | (data->fan_div[0] << 4); - asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); - break; - - case 1: /* fan 2 */ - reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); - reg = (reg & 0x3f) | (data->fan_div[1] << 6); - asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); - break; - - case 2: /* fan 3 */ - reg = asb100_read_value(client, ASB100_REG_PIN); - reg = (reg & 0x3f) | (data->fan_div[2] << 6); - asb100_write_value(client, ASB100_REG_PIN, reg); - break; - } - - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); - - up(&data->update_lock); - - return count; -} - -#define sysfs_fan(offset) \ -static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); - -sysfs_fan(1); -sysfs_fan(2); -sysfs_fan(3); - -#define device_create_file_fan(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -/* 4 Temp. Sensors */ -static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) -{ - int ret = 0; - - switch (nr) { - case 1: case 2: - ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg)); - break; - case 0: case 3: default: - ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg)); - break; - } - return ret; -} - -#define show_temp_reg(reg) \ -static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ -{ \ - struct asb100_data *data = asb100_update_device(dev); \ - return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ -} - -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_hyst); - -#define set_temp_reg(REG, reg) \ -static ssize_t set_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - switch (nr) { \ - case 1: case 2: \ - data->reg[nr] = LM75_TEMP_TO_REG(val); \ - break; \ - case 0: case 3: default: \ - data->reg[nr] = TEMP_TO_REG(val); \ - break; \ - } \ - asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ - data->reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp_reg(MAX, temp_max); -set_temp_reg(HYST, temp_hyst); - -#define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ -static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, num-1); \ -} \ -static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_max(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ - show_temp_max##num, set_temp_max##num); \ -static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_hyst(dev, buf, num-1); \ -} \ -static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_hyst(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_hyst##num, set_temp_hyst##num); - -sysfs_temp(1); -sysfs_temp(2); -sysfs_temp(3); -sysfs_temp(4); - -/* VID */ -#define device_create_file_temp(client, num) do { \ - device_create_file(&client->dev, &dev_attr_temp##num##_input); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ -} while (0) - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} - -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -/* VRM */ -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", data->vrm); -} - -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - return count; -} - -/* Alarms */ -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) - -/* 1 PWM */ -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); -} - -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm &= 0x80; /* keep the enable bit */ - data->pwm |= (0x0f & ASB100_PWM_TO_REG(val)); - asb100_write_value(client, ASB100_REG_PWM1, data->pwm); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); -} - -static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm &= 0x0f; /* keep the duty cycle bits */ - data->pwm |= (val ? 0x80 : 0x00); - asb100_write_value(client, ASB100_REG_PWM1, data->pwm); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, - show_pwm_enable1, set_pwm_enable1); -#define device_create_file_pwm1(client) do { \ - device_create_file(&new_client->dev, &dev_attr_pwm1); \ - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \ -} while (0) - -/* This function is called when: - asb100_driver is inserted (when this module is loaded), for each - available adapter - when a new adapter is inserted (and asb100_driver is still present) - */ -static int asb100_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, asb100_detect); -} - -static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, - int kind, struct i2c_client *new_client) -{ - int i, id, err; - struct asb100_data *data = i2c_get_clientdata(new_client); - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, "invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -ENODEV; - goto ERROR_SC_2; - } - } - asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0]->addr = force_subclients[2]; - data->lm75[1]->addr = force_subclients[3]; - } else { - int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val & 0x07); - data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); - } - - if(data->lm75[0]->addr == data->lm75[1]->addr) { - dev_err(&new_client->dev, "duplicate addresses 0x%x " - "for subclients\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_2; - } - - for (i = 0; i <= 1; i++) { - i2c_set_clientdata(data->lm75[i], NULL); - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &asb100_driver; - data->lm75[i]->flags = 0; - strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); - } - - if ((err = i2c_attach_client(data->lm75[0]))) { - dev_err(&new_client->dev, "subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[0]->addr); - goto ERROR_SC_2; - } - - if ((err = i2c_attach_client(data->lm75[1]))) { - dev_err(&new_client->dev, "subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[1]->addr); - goto ERROR_SC_3; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - kfree(data->lm75[1]); -ERROR_SC_1: - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int err; - struct i2c_client *new_client; - struct asb100_data *data; - - /* asb100 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("asb100.o: detect failed, " - "cannot attach to legacy adapter!\n"); - err = -ENODEV; - goto ERROR0; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - pr_debug("asb100.o: detect failed, " - "smbus byte data not supported!\n"); - err = -ENODEV; - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access asb100_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct asb100_data)); - - new_client = &data->client; - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &asb100_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The chip may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the chip will be reset to the right - bank. */ - if (kind < 0) { - - int val1 = asb100_read_value(new_client, ASB100_REG_BANK); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - /* If we're in bank 0 */ - if ( (!(val1 & 0x07)) && - /* Check for ASB100 ID (low byte) */ - ( ((!(val1 & 0x80)) && (val2 != 0x94)) || - /* Check for ASB100 ID (high byte ) */ - ((val1 & 0x80) && (val2 != 0x06)) ) ) { - pr_debug("asb100.o: detect failed, " - "bad chip id 0x%02x!\n", val2); - err = -ENODEV; - goto ERROR1; - } - - } /* kind < 0 */ - - /* We have either had a force parameter, or we have already detected - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - asb100_write_value(new_client, ASB100_REG_BANK, - (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - if ((val1 == 0x31) && (val2 == 0x06)) - kind = asb100; - else { - if (kind == 0) - dev_warn(&new_client->dev, "ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x.\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR1; - } - } - - /* Fill in remaining client fields and put it into the global list */ - strlcpy(new_client->name, "asb100", I2C_NAME_SIZE); - data->type = kind; - - 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 ERROR1; - - /* Attach secondary lm75 clients */ - if ((err = asb100_detect_subclients(adapter, address, kind, - new_client))) - goto ERROR2; - - /* Initialize the chip */ - asb100_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); - data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); - data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_alarms(new_client); - - device_create_file_pwm1(new_client); - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int asb100_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "client deregistration failed; " - "client not detached.\n"); - return err; - } - - if (i2c_get_clientdata(client)==NULL) { - /* subclients */ - kfree(client); - } else { - /* main client */ - kfree(i2c_get_clientdata(client)); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the chip between - bank switches. */ -static int asb100_read_value(struct i2c_client *client, u16 reg) -{ - struct asb100_data *data = i2c_get_clientdata(client); - struct i2c_client *cl; - int res, bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data (cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data (cl, 2)); - break; - case 0x55: /* MAX */ - default: - res = swab16(i2c_smbus_read_word_data (cl, 3)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); - - return res; -} - -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct asb100_data *data = i2c_get_clientdata(client); - struct i2c_client *cl; - int bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); -} - -static void asb100_init_client(struct i2c_client *client) -{ - struct asb100_data *data = i2c_get_clientdata(client); - int vid = 0; - - vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; - vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; - data->vrm = i2c_which_vrm(); - vid = vid_from_reg(vid, data->vrm); - - /* Start monitoring */ - asb100_write_value(client, ASB100_REG_CONFIG, - (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); -} - -static struct asb100_data *asb100_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "starting device update...\n"); - - /* 7 voltage inputs */ - for (i = 0; i < 7; i++) { - data->in[i] = asb100_read_value(client, - ASB100_REG_IN(i)); - data->in_min[i] = asb100_read_value(client, - ASB100_REG_IN_MIN(i)); - data->in_max[i] = asb100_read_value(client, - ASB100_REG_IN_MAX(i)); - } - - /* 3 fan inputs */ - for (i = 0; i < 3; i++) { - data->fan[i] = asb100_read_value(client, - ASB100_REG_FAN(i)); - data->fan_min[i] = asb100_read_value(client, - ASB100_REG_FAN_MIN(i)); - } - - /* 4 temperature inputs */ - for (i = 1; i <= 4; i++) { - data->temp[i-1] = asb100_read_value(client, - ASB100_REG_TEMP(i)); - data->temp_max[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_MAX(i)); - data->temp_hyst[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_HYST(i)); - } - - /* VID and fan divisors */ - i = asb100_read_value(client, ASB100_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (asb100_read_value(client, - ASB100_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (asb100_read_value(client, - ASB100_REG_PIN) >> 6) & 0x03; - - /* PWM */ - data->pwm = asb100_read_value(client, ASB100_REG_PWM1); - - /* alarms */ - data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + - (asb100_read_value(client, ASB100_REG_ALARM2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - - dev_dbg(&client->dev, "... device update complete\n"); - } - - up(&data->update_lock); - - return data; -} - -static int __init asb100_init(void) -{ - return i2c_add_driver(&asb100_driver); -} - -static void __exit asb100_exit(void) -{ - i2c_del_driver(&asb100_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("ASB100 Bach driver"); -MODULE_LICENSE("GPL"); - -module_init(asb100_init); -module_exit(asb100_exit); - diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c deleted file mode 100644 index 0bcf82b4c07..00000000000 --- a/drivers/i2c/chips/atxp1.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - atxp1.c - kernel module for setting CPU VID and general purpose - I/Os using the Attansic ATXP1 chip. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); -MODULE_VERSION("0.6.2"); -MODULE_AUTHOR("Sebastian Witt "); - -#define ATXP1_VID 0x00 -#define ATXP1_CVID 0x01 -#define ATXP1_GPIO1 0x06 -#define ATXP1_GPIO2 0x0a -#define ATXP1_VIDENA 0x20 -#define ATXP1_VIDMASK 0x1f -#define ATXP1_GPIO1MASK 0x0f - -static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -SENSORS_INSMOD_1(atxp1); - -static int atxp1_attach_adapter(struct i2c_adapter * adapter); -static int atxp1_detach_client(struct i2c_client * client); -static struct atxp1_data * atxp1_update_device(struct device *dev); -static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); - -static struct i2c_driver atxp1_driver = { - .owner = THIS_MODULE, - .name = "atxp1", - .flags = I2C_DF_NOTIFY, - .attach_adapter = atxp1_attach_adapter, - .detach_client = atxp1_detach_client, -}; - -struct atxp1_data { - struct i2c_client client; - struct semaphore update_lock; - unsigned long last_updated; - u8 valid; - struct { - u8 vid; /* VID output register */ - u8 cpu_vid; /* VID input from CPU */ - u8 gpio1; /* General purpose I/O register 1 */ - u8 gpio2; /* General purpose I/O register 2 */ - } reg; - u8 vrm; /* Detected CPU VRM */ -}; - -static struct atxp1_data * atxp1_update_device(struct device *dev) -{ - struct i2c_client *client; - struct atxp1_data *data; - - client = to_i2c_client(dev); - data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - - /* Update local register data */ - data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); - data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); - data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); - data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); - - data->valid = 1; - } - - up(&data->update_lock); - - return(data); -} - -/* sys file functions for cpu0_vid */ -static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); - - return size; -} - -static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - char vid; - char cvid; - unsigned int vcore; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - vcore = simple_strtoul(buf, NULL, 10); - vcore /= 25; - vcore *= 25; - - /* Calculate VID */ - vid = vid_to_reg(vcore, data->vrm); - - if (vid < 0) { - dev_err(dev, "VID calculation failed.\n"); - return -1; - } - - /* If output enabled, use control register value. Otherwise original CPU VID */ - if (data->reg.vid & ATXP1_VIDENA) - cvid = data->reg.vid & ATXP1_VIDMASK; - else - cvid = data->reg.cpu_vid; - - /* Nothing changed, aborting */ - if (vid == cvid) - return count; - - dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); - - /* Write every 25 mV step to increase stability */ - if (cvid > vid) { - for (; cvid >= vid; cvid--) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } - } - else { - for (; cvid <= vid; cvid++) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } - } - - data->valid = 0; - - return count; -} - -/* CPU core reference voltage - unit: millivolt -*/ -static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); - -/* sys file functions for GPIO1 */ -static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); - - return size; -} - -static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - unsigned int value; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - value = simple_strtoul(buf, NULL, 16); - - value &= ATXP1_GPIO1MASK; - - if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); - - i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); - - data->valid = 0; - } - - return count; -} - -/* GPIO1 data register - unit: Four bit as hex (e.g. 0x0f) -*/ -static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); - -/* sys file functions for GPIO2 */ -static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "0x%02x\n", data->reg.gpio2); - - return size; -} - -static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - unsigned int value; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - value = simple_strtoul(buf, NULL, 16) & 0xff; - - if (value != data->reg.gpio2) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); - - i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); - - data->valid = 0; - } - - return count; -} - -/* GPIO2 data register - unit: Eight bit as hex (e.g. 0xff) -*/ -static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); - - -static int atxp1_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, &atxp1_detect); -}; - -static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client * new_client; - struct atxp1_data * data; - int err = 0; - u8 temp; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - memset(data, 0, sizeof(struct atxp1_data)); - new_client = &data->client; - i2c_set_clientdata(new_client, data); - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &atxp1_driver; - new_client->flags = 0; - - /* Detect ATXP1, checking if vendor ID registers are all zero */ - if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && - (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && - (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && - (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { - - /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) - * showing the same as register 0x00 */ - temp = i2c_smbus_read_byte_data(new_client, 0x00); - - if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && - (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) - goto exit_free; - } - - /* Get VRM */ - data->vrm = i2c_which_vrm(); - - if ((data->vrm != 90) && (data->vrm != 91)) { - dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", - data->vrm / 10, data->vrm % 10); - goto exit_free; - } - - strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); - - data->valid = 0; - - init_MUTEX(&data->update_lock); - - err = i2c_attach_client(new_client); - - if (err) - { - dev_err(&new_client->dev, "Attach client error.\n"); - goto exit_free; - } - - device_create_file(&new_client->dev, &dev_attr_gpio1); - device_create_file(&new_client->dev, &dev_attr_gpio2); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - dev_info(&new_client->dev, "Using VRM: %d.%d\n", - data->vrm / 10, data->vrm % 10); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -}; - -static int atxp1_detach_client(struct i2c_client * client) -{ - int err; - - err = i2c_detach_client(client); - - if (err) - dev_err(&client->dev, "Failed to detach client.\n"); - else - kfree(i2c_get_clientdata(client)); - - return err; -}; - -static int __init atxp1_init(void) -{ - return i2c_add_driver(&atxp1_driver); -}; - -static void __exit atxp1_exit(void) -{ - i2c_del_driver(&atxp1_driver); -}; - -module_init(atxp1_init); -module_exit(atxp1_exit); diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c deleted file mode 100644 index 5360d58804f..00000000000 --- a/drivers/i2c/chips/ds1621.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - ds1621.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Christian W. Zuckschwerdt 2000-11-23 - based on lm75.c by Frodo Looijaard - Ported to Linux 2.6 by Aurelien Jarno with - the help of Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ds1621); -static int polarity = -1; -module_param(polarity, int, 0); -MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); - -/* Many DS1621 constants specified below */ -/* Config register used for detection */ -/* 7 6 5 4 3 2 1 0 */ -/* |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 - -/* The DS1621 registers */ -#define DS1621_REG_TEMP 0xAA /* word, RO */ -#define DS1621_REG_TEMP_MIN 0xA1 /* word, RW */ -#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 -#define DS1621_ALARM_TEMP_LOW 0x20 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define ALARMS_FROM_REG(val) ((val) & \ - (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) - -/* Each client has this additional data */ -struct ds1621_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_min, temp_max; /* Register values, word */ - u8 conf; /* Register encoding, combined */ -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter); -static int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind); -static void ds1621_init_client(struct i2c_client *client); -static int ds1621_detach_client(struct i2c_client *client); -static struct ds1621_data *ds1621_update_client(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver ds1621_driver = { - .owner = THIS_MODULE, - .name = "ds1621", - .id = I2C_DRIVERID_DS1621, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1621_attach_adapter, - .detach_client = ds1621_detach_client, -}; - -/* 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. */ -static int ds1621_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == DS1621_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* 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. */ -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == DS1621_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void ds1621_init_client(struct i2c_client *client) -{ - int reg = ds1621_read_value(client, DS1621_REG_CONF); - /* switch to continuous conversion mode */ - reg &= ~ DS1621_REG_CONFIG_1SHOT; - - /* setup output polarity */ - if (polarity == 0) - reg &= ~DS1621_REG_CONFIG_POLARITY; - else if (polarity == 1) - reg |= DS1621_REG_CONFIG_POLARITY; - - ds1621_write_value(client, DS1621_REG_CONF, reg); - - /* start conversion */ - i2c_smbus_write_byte(client, DS1621_COM_START); -} - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct ds1621_data *data = ds1621_update_client(dev); \ - return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ -} - -show(temp); -show(temp_min); -show(temp_max); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct ds1621_data *data = ds1621_update_client(dev); \ - u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ - \ - down(&data->update_lock); \ - data->value = val; \ - ds1621_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp(min, temp_min, DS1621_REG_TEMP_MIN); -set_temp(max, temp_max, DS1621_REG_TEMP_MAX); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct ds1621_data *data = ds1621_update_client(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); - - -static int ds1621_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ds1621_detect); -} - -/* This function is called by i2c_detect */ -int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int conf, temp; - struct i2c_client *new_client; - struct ds1621_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA - | I2C_FUNC_SMBUS_WRITE_BYTE)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct ds1621_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &ds1621_driver; - new_client->flags = 0; - - - /* 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_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; - temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN); - if (temp & 0x007f) - goto exit_free; - temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX); - if (temp & 0x007f) - goto exit_free; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ds1621; - - /* Fill in remaining client fields and put it into the global list */ - strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the DS1621 chip */ - ds1621_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - exit_free: - kfree(data); - exit: - return err; -} - -static int ds1621_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 struct ds1621_data *ds1621_update_client(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); - u8 new_conf; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting ds1621 update\n"); - - data->conf = ds1621_read_value(client, DS1621_REG_CONF); - - data->temp = ds1621_read_value(client, DS1621_REG_TEMP); - - data->temp_min = ds1621_read_value(client, - DS1621_REG_TEMP_MIN); - data->temp_max = ds1621_read_value(client, - DS1621_REG_TEMP_MAX); - - /* reset alarms if necessary */ - new_conf = data->conf; - if (data->temp < data->temp_min) - new_conf &= ~DS1621_ALARM_TEMP_LOW; - if (data->temp > data->temp_max) - new_conf &= ~DS1621_ALARM_TEMP_HIGH; - if (data->conf != new_conf) - ds1621_write_value(client, DS1621_REG_CONF, - new_conf); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init ds1621_init(void) -{ - return i2c_add_driver(&ds1621_driver); -} - -static void __exit ds1621_exit(void) -{ - i2c_del_driver(&ds1621_driver); -} - - -MODULE_AUTHOR("Christian W. Zuckschwerdt "); -MODULE_DESCRIPTION("DS1621 driver"); -MODULE_LICENSE("GPL"); - -module_init(ds1621_init); -module_exit(ds1621_exit); diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c deleted file mode 100644 index da411741c2c..00000000000 --- a/drivers/i2c/chips/fscher.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * fscher.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003, 2004 Reinhard Nissl - * - * 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 hermes chip, - * module based on fscpos.c - * Copyright (C) 2000 Hermann Jung - * Copyright (C) 1998, 1999 Frodo Looijaard - * and Philip Edelbrock - */ - -#include -#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(fscher); - -/* - * The FSCHER registers - */ - -/* chip identification */ -#define FSCHER_REG_IDENT_0 0x00 -#define FSCHER_REG_IDENT_1 0x01 -#define FSCHER_REG_IDENT_2 0x02 -#define FSCHER_REG_REVISION 0x03 - -/* global control and status */ -#define FSCHER_REG_EVENT_STATE 0x04 -#define FSCHER_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCHER_REG_WDOG_PRESET 0x28 -#define FSCHER_REG_WDOG_STATE 0x23 -#define FSCHER_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCHER_REG_FAN0_MIN 0x55 -#define FSCHER_REG_FAN0_ACT 0x0e -#define FSCHER_REG_FAN0_STATE 0x0d -#define FSCHER_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCHER_REG_FAN1_MIN 0x65 -#define FSCHER_REG_FAN1_ACT 0x6b -#define FSCHER_REG_FAN1_STATE 0x62 -#define FSCHER_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCHER_REG_FAN2_MIN 0xb5 -#define FSCHER_REG_FAN2_ACT 0xbb -#define FSCHER_REG_FAN2_STATE 0xb2 -#define FSCHER_REG_FAN2_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCHER_REG_VOLT_12 0x45 -#define FSCHER_REG_VOLT_5 0x42 -#define FSCHER_REG_VOLT_BATT 0x48 - -/* temperature 0 */ -#define FSCHER_REG_TEMP0_ACT 0x64 -#define FSCHER_REG_TEMP0_STATE 0x71 - -/* temperature 1 */ -#define FSCHER_REG_TEMP1_ACT 0x32 -#define FSCHER_REG_TEMP1_STATE 0x81 - -/* temperature 2 */ -#define FSCHER_REG_TEMP2_ACT 0x35 -#define FSCHER_REG_TEMP2_STATE 0x91 - -/* - * Functions declaration - */ - -static int fscher_attach_adapter(struct i2c_adapter *adapter); -static int fscher_detect(struct i2c_adapter *adapter, int address, int kind); -static int fscher_detach_client(struct i2c_client *client); -static struct fscher_data *fscher_update_device(struct device *dev); -static void fscher_init_client(struct i2c_client *client); - -static int fscher_read_value(struct i2c_client *client, u8 reg); -static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver fscher_driver = { - .owner = THIS_MODULE, - .name = "fscher", - .id = I2C_DRIVERID_FSCHER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscher_attach_adapter, - .detach_client = fscher_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct fscher_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero 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 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery voltage */ - 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 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - -/* - * Sysfs stuff - */ - -#define sysfs_r(kind, sub, offset, reg) \ -static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \ -static ssize_t show_##kind##offset##sub (struct device *, struct device_attribute *attr, char *); \ -static ssize_t show_##kind##offset##sub (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct fscher_data *data = fscher_update_device(dev); \ - return show_##kind##sub(data, buf, (offset)); \ -} - -#define sysfs_w(kind, sub, offset, reg) \ -static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \ -static ssize_t set_##kind##offset##sub (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct fscher_data *data = i2c_get_clientdata(client); \ - return set_##kind##sub(client, data, buf, count, (offset), reg); \ -} - -#define sysfs_rw_n(kind, sub, offset, reg) \ -sysfs_r(kind, sub, offset, reg) \ -sysfs_w(kind, sub, offset, reg) \ -static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, show_##kind##offset##sub, set_##kind##offset##sub); - -#define sysfs_rw(kind, sub, reg) \ -sysfs_r(kind, sub, 0, reg) \ -sysfs_w(kind, sub, 0, reg) \ -static DEVICE_ATTR(kind##sub, S_IRUGO | S_IWUSR, show_##kind##0##sub, set_##kind##0##sub); - -#define sysfs_ro_n(kind, sub, offset, reg) \ -sysfs_r(kind, sub, offset, reg) \ -static DEVICE_ATTR(kind##offset##sub, S_IRUGO, show_##kind##offset##sub, NULL); - -#define sysfs_ro(kind, sub, reg) \ -sysfs_r(kind, sub, 0, reg) \ -static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0##sub, NULL); - -#define sysfs_fan(offset, reg_status, reg_min, reg_ripple, reg_act) \ -sysfs_rw_n(pwm, , offset, reg_min) \ -sysfs_rw_n(fan, _status, offset, reg_status) \ -sysfs_rw_n(fan, _div , offset, reg_ripple) \ -sysfs_ro_n(fan, _input , offset, reg_act) - -#define sysfs_temp(offset, reg_status, reg_act) \ -sysfs_rw_n(temp, _status, offset, reg_status) \ -sysfs_ro_n(temp, _input , offset, reg_act) - -#define sysfs_in(offset, reg_act) \ -sysfs_ro_n(in, _input, offset, reg_act) - -#define sysfs_revision(reg_revision) \ -sysfs_ro(revision, , reg_revision) - -#define sysfs_alarms(reg_events) \ -sysfs_ro(alarms, , reg_events) - -#define sysfs_control(reg_control) \ -sysfs_rw(control, , reg_control) - -#define sysfs_watchdog(reg_control, reg_status, reg_preset) \ -sysfs_rw(watchdog, _control, reg_control) \ -sysfs_rw(watchdog, _status , reg_status) \ -sysfs_rw(watchdog, _preset , reg_preset) - -sysfs_fan(1, FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_MIN, - FSCHER_REG_FAN0_RIPPLE, FSCHER_REG_FAN0_ACT) -sysfs_fan(2, FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_MIN, - FSCHER_REG_FAN1_RIPPLE, FSCHER_REG_FAN1_ACT) -sysfs_fan(3, FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_MIN, - FSCHER_REG_FAN2_RIPPLE, FSCHER_REG_FAN2_ACT) - -sysfs_temp(1, FSCHER_REG_TEMP0_STATE, FSCHER_REG_TEMP0_ACT) -sysfs_temp(2, FSCHER_REG_TEMP1_STATE, FSCHER_REG_TEMP1_ACT) -sysfs_temp(3, FSCHER_REG_TEMP2_STATE, FSCHER_REG_TEMP2_ACT) - -sysfs_in(0, FSCHER_REG_VOLT_12) -sysfs_in(1, FSCHER_REG_VOLT_5) -sysfs_in(2, FSCHER_REG_VOLT_BATT) - -sysfs_revision(FSCHER_REG_REVISION) -sysfs_alarms(FSCHER_REG_EVENTS) -sysfs_control(FSCHER_REG_CONTROL) -sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET) - -#define device_create_file_fan(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_status); \ - device_create_file(&client->dev, &dev_attr_pwm##offset); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -} while (0) - -#define device_create_file_temp(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_temp##offset##_status); \ - device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -} while (0) - -#define device_create_file_in(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -} while (0) - -#define device_create_file_revision(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_revision); \ -} while (0) - -#define device_create_file_alarms(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_alarms); \ -} while (0) - -#define device_create_file_control(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_control); \ -} while (0) - -#define device_create_file_watchdog(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_watchdog_status); \ - device_create_file(&client->dev, &dev_attr_watchdog_control); \ - device_create_file(&client->dev, &dev_attr_watchdog_preset); \ -} while (0) - -/* - * Real code - */ - -static int fscher_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, fscher_detect); -} - -static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct fscher_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 i2c_smbus_read_byte_data. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct fscher_data)); - - /* The common I2C client data is placed right before the - * Hermes-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &fscher_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscher parameter */ - if (kind < 0) { - if ((i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ - || (i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ - || (i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */ - goto exit_free; - } - - /* Fill in the remaining client fields and put it into the - * global list */ - strlcpy(new_client->name, "fscher", 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; - - fscher_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file_revision(new_client); - device_create_file_alarms(new_client); - device_create_file_control(new_client); - device_create_file_watchdog(new_client); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int fscher_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 fscher_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 fscher_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 FSC Hermes. */ -static void fscher_init_client(struct i2c_client *client) -{ - struct fscher_data *data = i2c_get_clientdata(client); - - /* Read revision from chip */ - data->revision = fscher_read_value(client, FSCHER_REG_REVISION); -} - -static struct fscher_data *fscher_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct fscher_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - - dev_dbg(&client->dev, "Starting fscher update\n"); - - data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); - data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); - data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); - data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); - data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); - data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); - - data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); - data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); - data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); - - data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); - data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); - data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); - data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); - data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); - data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); - data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); - data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); - data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); - data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); - data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); - data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); - - data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - - - -#define FAN_INDEX_FROM_NUM(nr) ((nr) - 1) - -static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 0..1, 3..7 reserved => mask with 0x04 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; - - down(&data->update_lock); - data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0..1, 3..7 reserved => mask with 0x04 */ - return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04); -} - -static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v; - fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]); -} - -static ssize_t set_fan_div(struct i2c_client *client, struct fscher_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_div value %ld not " - "supported. Choose one of 2, 4 or 8!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - - /* bits 2..7 reserved => mask with 0x03 */ - data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03; - data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v; - - fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03)); -} - -#define RPM_FROM_REG(val) (val*60) - -static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)])); -} - - - -#define TEMP_INDEX_FROM_NUM(nr) ((nr) - 1) - -static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 2..7 reserved, 0 read only => mask with 0x02 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; - - down(&data->update_lock); - data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03); -} - -#define TEMP_FROM_REG(val) (((val) - 128) * 1000) - -static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)])); -} - -/* - * The final conversion is specified in sensors.conf, as it depends on - * mainboard specific values. We export the registers contents as - * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much - * sense per se, but it minimizes the conversions count and keeps the - * values within a usual range. - */ -#define VOLT_FROM_REG(val) ((val) * 10) - -static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr])); -} - - - -static ssize_t show_revision(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->revision); -} - - - -static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2, 5..6 reserved => mask with 0x9b */ - return sprintf(buf, "%u\n", data->global_event & 0x9b); -} - - - -static ssize_t set_control(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 1..7 reserved => mask with 0x01 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; - - down(&data->update_lock); - data->global_control &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_control(struct fscher_data *data, char *buf, int nr) -{ - /* bits 1..7 reserved => mask with 0x01 */ - return sprintf(buf, "%u\n", data->global_control & 0x01); -} - - - -static ssize_t set_watchdog_control(struct i2c_client *client, struct - fscher_data *data, const char *buf, size_t count, - int nr, int reg) -{ - /* bits 0..3 reserved => mask with 0xf0 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; - - down(&data->update_lock); - data->watchdog[2] &= ~0xf0; - data->watchdog[2] |= v; - fscher_write_value(client, reg, data->watchdog[2]); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */ - return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0); -} - -static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 0, 2..7 reserved => mask with 0x02 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; - - down(&data->update_lock); - data->watchdog[1] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0, 2..7 reserved => mask with 0x02 */ - return sprintf(buf, "%u\n", data->watchdog[1] & 0x02); -} - -static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; - - down(&data->update_lock); - data->watchdog[0] = v; - fscher_write_value(client, reg, data->watchdog[0]); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->watchdog[0]); -} - -static int __init sensors_fscher_init(void) -{ - return i2c_add_driver(&fscher_driver); -} - -static void __exit sensors_fscher_exit(void) -{ - i2c_del_driver(&fscher_driver); -} - -MODULE_AUTHOR("Reinhard Nissl "); -MODULE_DESCRIPTION("FSC Hermes driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_fscher_init); -module_exit(sensors_fscher_exit); diff --git a/drivers/i2c/chips/fscpos.c b/drivers/i2c/chips/fscpos.c deleted file mode 100644 index 3beaa6191ef..00000000000 --- a/drivers/i2c/chips/fscpos.c +++ /dev/null @@ -1,641 +0,0 @@ -/* - 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; - } - - down(&data->update_lock); - /* 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]); - up(&data->update_lock); - 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; - - down(&data->update_lock); - data->pwm[nr - 1] = v; - fscpos_write_value(client, reg, data->pwm[nr - 1]); - up(&data->update_lock); - 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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; - - down(&data->update_lock); - data->wdog_control &= ~0xf0; - data->wdog_control |= v; - fscpos_write_value(client, reg, data->wdog_control); - up(&data->update_lock); - 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; - } - - down(&data->update_lock); - data->wdog_state &= ~v; - fscpos_write_value(client, reg, v); - up(&data->update_lock); - 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) -{ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; - - down(&data->update_lock); - data->wdog_preset = v; - fscpos_write_value(client, reg, data->wdog_preset); - up(&data->update_lock); - return count; -} - -/* Event */ -static ssize_t show_event(struct device *dev, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, 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, struct device_attribute *attr, \ - 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 --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c deleted file mode 100644 index 6bedf729dcf..00000000000 --- a/drivers/i2c/chips/gl518sm.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 1998, 1999 Frodo Looijaard and - * Kyosti Malkki - * Copyright (C) 2004 Hong-Gunn Chew and - * Jean Delvare - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Ported to Linux 2.6 by Hong-Gunn Chew with the help of Jean Delvare - * and advice of Greg Kroah-Hartman. - * - * Notes about the port: - * Release 0x00 of the GL518SM chipset doesn't support reading of in0, - * in1 nor in2. The original driver had an ugly workaround to get them - * anyway (changing limits and watching alarms trigger and wear off). - * We did not keep that part of the original driver in the Linux 2.6 - * version, since it was making the driver significantly more complex - * with no real benefit. - * - * History: - * 2004-01-28 Original port. (Hong-Gunn Chew) - * 2004-01-31 Code review and approval. (Jean Delvare) - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); - -/* Many GL518 constants specified below */ - -/* The GL518 registers */ -#define GL518_REG_CHIP_ID 0x00 -#define GL518_REG_REVISION 0x01 -#define GL518_REG_VENDOR_ID 0x02 -#define GL518_REG_CONF 0x03 -#define GL518_REG_TEMP_IN 0x04 -#define GL518_REG_TEMP_MAX 0x05 -#define GL518_REG_TEMP_HYST 0x06 -#define GL518_REG_FAN_COUNT 0x07 -#define GL518_REG_FAN_LIMIT 0x08 -#define GL518_REG_VIN1_LIMIT 0x09 -#define GL518_REG_VIN2_LIMIT 0x0a -#define GL518_REG_VIN3_LIMIT 0x0b -#define GL518_REG_VDD_LIMIT 0x0c -#define GL518_REG_VIN3 0x0d -#define GL518_REG_MISC 0x0f -#define GL518_REG_ALARM 0x10 -#define GL518_REG_MASK 0x11 -#define GL518_REG_INT 0x12 -#define GL518_REG_VIN2 0x13 -#define GL518_REG_VIN1 0x14 -#define GL518_REG_VDD 0x15 - - -/* - * Conversions. Rounding and limit checking is only done on the TO_REG - * variants. Note that you should be a bit careful with which arguments - * these macros are called: arguments may be evaluated more than once. - * Fixing this is just not worth it. - */ - -#define RAW_FROM_REG(val) val - -#define BOOL_FROM_REG(val) ((val)?0:1) -#define BOOL_TO_REG(val) ((val)?0:1) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \ - (val)-500:(val)+500)/1000)+119),0,255)) -#define TEMP_FROM_REG(val) (((val) - 119) * 1000) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - long rpmdiv; - if (rpm == 0) - return 0; - rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; - return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); -} -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) -#define IN_FROM_REG(val) ((val)*19) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) -#define VDD_FROM_REG(val) (((val)*95+2)/4) - -#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) -#define DIV_FROM_REG(val) (1 << (val)) - -#define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) -#define BEEP_MASK_FROM_REG(val) ((val) & 0x7f) - -/* Each client has this additional data */ -struct gl518_data { - struct i2c_client client; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 voltage_in[4]; /* Register values; [0] = VDD */ - u8 voltage_min[4]; /* Register values; [0] = VDD */ - u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ - u8 fan_in[2]; - u8 fan_min[2]; - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 fan_auto1; /* Boolean */ - u8 temp_in; /* Register values */ - u8 temp_max; /* Register values */ - u8 temp_hyst; /* Register values */ - u8 alarms; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 beep_mask; /* Register value */ - u8 beep_enable; /* Boolean */ -}; - -static int gl518_attach_adapter(struct i2c_adapter *adapter); -static int gl518_detect(struct i2c_adapter *adapter, int address, int kind); -static void gl518_init_client(struct i2c_client *client); -static int gl518_detach_client(struct i2c_client *client); -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct gl518_data *gl518_update_device(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - .owner = THIS_MODULE, - .name = "gl518sm", - .id = I2C_DRIVERID_GL518, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl518_attach_adapter, - .detach_client = gl518_detach_client, -}; - -/* - * Sysfs stuff - */ - -#define show(type, suffix, value) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ -} - -#define show_fan(suffix, value, index) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ - DIV_FROM_REG(data->fan_div[index]))); \ -} - -show(TEMP, temp_input1, temp_in); -show(TEMP, temp_max1, temp_max); -show(TEMP, temp_hyst1, temp_hyst); -show(BOOL, fan_auto1, fan_auto1); -show_fan(fan_input1, fan_in, 0); -show_fan(fan_input2, fan_in, 1); -show_fan(fan_min1, fan_min, 0); -show_fan(fan_min2, fan_min, 1); -show(DIV, fan_div1, fan_div[0]); -show(DIV, fan_div2, fan_div[1]); -show(VDD, in_input0, voltage_in[0]); -show(IN, in_input1, voltage_in[1]); -show(IN, in_input2, voltage_in[2]); -show(IN, in_input3, voltage_in[3]); -show(VDD, in_min0, voltage_min[0]); -show(IN, in_min1, voltage_min[1]); -show(IN, in_min2, voltage_min[2]); -show(IN, in_min3, voltage_min[3]); -show(VDD, in_max0, voltage_max[0]); -show(IN, in_max1, voltage_max[1]); -show(IN, in_max2, voltage_max[2]); -show(IN, in_max3, voltage_max[3]); -show(RAW, alarms, alarms); -show(BOOL, beep_enable, beep_enable); -show(BEEP_MASK, beep_mask, beep_mask); - -#define set(type, suffix, value, reg) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = type##_TO_REG(val); \ - gl518_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -#define set_bits(type, suffix, value, reg, mask, shift) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ - int regvalue; \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - regvalue = gl518_read_value(client, reg); \ - data->value = type##_TO_REG(val); \ - regvalue = (regvalue & ~mask) | (data->value << shift); \ - gl518_write_value(client, reg, regvalue); \ - up(&data->update_lock); \ - return count; \ -} - -#define set_low(type, suffix, value, reg) \ - set_bits(type, suffix, value, reg, 0x00ff, 0) -#define set_high(type, suffix, value, reg) \ - set_bits(type, suffix, value, reg, 0xff00, 8) - -set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); -set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); -set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); -set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); -set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); -set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); -set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); -set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); -set_low(IN, in_min3, voltage_min[3], GL518_REG_VIN3_LIMIT); -set_high(VDD, in_max0, voltage_max[0], GL518_REG_VDD_LIMIT); -set_high(IN, in_max1, voltage_max[1], GL518_REG_VIN1_LIMIT); -set_high(IN, in_max2, voltage_max[2], GL518_REG_VIN2_LIMIT); -set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); -set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); -set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); - -static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[0])); - regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[1] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[1])); - regvalue = (regvalue & 0xff00) | data->fan_min[1]; - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, - show_temp_hyst1, set_temp_hyst1); -static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); -static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); -static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); -static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); -static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0); -static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1); -static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2); -static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3); -static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0); -static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1); -static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2); -static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, - show_beep_enable, set_beep_enable); -static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, - show_beep_mask, set_beep_mask); - -/* - * Real code - */ - -static int gl518_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, gl518_detect); -} - -static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl518_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl518_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct gl518_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) - goto exit_free; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); - if (i == 0x00) { - kind = gl518sm_r00; - } else if (i == 0x80) { - kind = gl518sm_r80; - } else { - if (kind <= 0) - dev_info(&adapter->dev, - "Ignoring 'force' parameter for unknown " - "chip at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto exit_free; - } - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the GL518SM chip */ - data->alarm_mask = 0xff; - data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; - gl518_init_client((struct i2c_client *) new_client); - - /* Register sysfs hooks */ - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_fan1_auto); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_beep_enable); - device_create_file(&new_client->dev, &dev_attr_beep_mask); - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -exit_free: - kfree(data); -exit: - return err; -} - - -/* Called when we have found a new GL518SM. - Note that we preserve D4:NoFan2 and D2:beep_enable. */ -static void gl518_init_client(struct i2c_client *client) -{ - /* Make sure we leave D7:Reset untouched */ - u8 regvalue = gl518_read_value(client, GL518_REG_CONF) & 0x7f; - - /* Comparator mode (D3=0), standby mode (D6=0) */ - gl518_write_value(client, GL518_REG_CONF, (regvalue &= 0x37)); - - /* Never interrupts */ - gl518_write_value(client, GL518_REG_MASK, 0x00); - - /* Clear status register (D5=1), start (D6=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x20 | regvalue); - gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); -} - -static int gl518_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static struct gl518_data *gl518_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int val; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting gl518 update\n"); - - data->alarms = gl518_read_value(client, GL518_REG_INT); - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - - val = gl518_read_value(client, GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_COUNT); - data->fan_in[0] = (val >> 8) & 0xff; - data->fan_in[1] = val & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); - data->temp_max = - gl518_read_value(client, GL518_REG_TEMP_MAX); - data->temp_hyst = - gl518_read_value(client, GL518_REG_TEMP_HYST); - - val = gl518_read_value(client, GL518_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - data->fan_auto1 = (val >> 3) & 0x01; - - data->alarms &= data->alarm_mask; - - val = gl518_read_value(client, GL518_REG_CONF); - data->beep_enable = (val >> 2) & 1; - - if (data->type != gl518sm_r00) { - data->voltage_in[0] = - gl518_read_value(client, GL518_REG_VDD); - data->voltage_in[1] = - gl518_read_value(client, GL518_REG_VIN1); - data->voltage_in[2] = - gl518_read_value(client, GL518_REG_VIN2); - } - data->voltage_in[3] = - gl518_read_value(client, GL518_REG_VIN3); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_gl518sm_init(void) -{ - return i2c_add_driver(&gl518_driver); -} - -static void __exit sensors_gl518sm_exit(void) -{ - i2c_del_driver(&gl518_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Kyosti Malkki and " - "Hong-Gunn Chew "); -MODULE_DESCRIPTION("GL518SM driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_gl518sm_init); -module_exit(sensors_gl518sm_exit); diff --git a/drivers/i2c/chips/gl520sm.c b/drivers/i2c/chips/gl520sm.c deleted file mode 100644 index a13a504f5bf..00000000000 --- a/drivers/i2c/chips/gl520sm.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - Copyright (c) 2005 Maarten Deprez - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -/* Type of the extra sensor */ -static unsigned short extra_sensor_type; -module_param(extra_sensor_type, ushort, 0); -MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(gl520sm); - -/* Many GL520 constants specified below -One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _IN4 access the same register -*/ - -/* The GL520 registers */ -#define GL520_REG_CHIP_ID 0x00 -#define GL520_REG_REVISION 0x01 -#define GL520_REG_CONF 0x03 -#define GL520_REG_MASK 0x11 - -#define GL520_REG_VID_INPUT 0x02 - -#define GL520_REG_IN0_INPUT 0x15 -#define GL520_REG_IN0_LIMIT 0x0c -#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT -#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT - -#define GL520_REG_IN1_INPUT 0x14 -#define GL520_REG_IN1_LIMIT 0x09 -#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT -#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT - -#define GL520_REG_IN2_INPUT 0x13 -#define GL520_REG_IN2_LIMIT 0x0a -#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT -#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT - -#define GL520_REG_IN3_INPUT 0x0d -#define GL520_REG_IN3_LIMIT 0x0b -#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT -#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT - -#define GL520_REG_IN4_INPUT 0x0e -#define GL520_REG_IN4_MAX 0x17 -#define GL520_REG_IN4_MIN 0x18 - -#define GL520_REG_TEMP1_INPUT 0x04 -#define GL520_REG_TEMP1_MAX 0x05 -#define GL520_REG_TEMP1_MAX_HYST 0x06 - -#define GL520_REG_TEMP2_INPUT 0x0e -#define GL520_REG_TEMP2_MAX 0x17 -#define GL520_REG_TEMP2_MAX_HYST 0x18 - -#define GL520_REG_FAN_INPUT 0x07 -#define GL520_REG_FAN_MIN 0x08 -#define GL520_REG_FAN_DIV 0x0f -#define GL520_REG_FAN_OFF GL520_REG_FAN_DIV - -#define GL520_REG_ALARMS 0x12 -#define GL520_REG_BEEP_MASK 0x10 -#define GL520_REG_BEEP_ENABLE GL520_REG_CONF - -/* - * Function declarations - */ - -static int gl520_attach_adapter(struct i2c_adapter *adapter); -static int gl520_detect(struct i2c_adapter *adapter, int address, int kind); -static void gl520_init_client(struct i2c_client *client); -static int gl520_detach_client(struct i2c_client *client); -static int gl520_read_value(struct i2c_client *client, u8 reg); -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct gl520_data *gl520_update_device(struct device *dev); - -/* Driver data */ -static struct i2c_driver gl520_driver = { - .owner = THIS_MODULE, - .name = "gl520sm", - .id = I2C_DRIVERID_GL520, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl520_attach_adapter, - .detach_client = gl520_detach_client, -}; - -/* Client data */ -struct gl520_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until the following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - u8 vid; - u8 vrm; - u8 in_input[5]; /* [0] = VVD */ - u8 in_min[5]; /* [0] = VDD */ - u8 in_max[5]; /* [0] = VDD */ - u8 fan_input[2]; - u8 fan_min[2]; - u8 fan_div[2]; - u8 fan_off; - u8 temp_input[2]; - u8 temp_max[2]; - u8 temp_max_hyst[2]; - u8 alarms; - u8 beep_enable; - u8 beep_mask; - u8 alarm_mask; - u8 two_temps; -}; - -/* - * Sysfs stuff - */ - -#define sysfs_r(type, n, item, reg) \ -static ssize_t get_##type##item (struct gl520_data *, char *, int); \ -static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ -static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl520_data *data = gl520_update_device(dev); \ - return get_##type##item(data, buf, (n)); \ -} - -#define sysfs_w(type, n, item, reg) \ -static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ -static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl520_data *data = i2c_get_clientdata(client); \ - return set_##type##item(client, data, buf, count, (n), reg); \ -} - -#define sysfs_rw_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -sysfs_w(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); - -#define sysfs_ro_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); - -#define sysfs_rw(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -sysfs_w(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); - -#define sysfs_ro(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); - - -#define sysfs_vid(n) \ -sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) - -#define device_create_file_vid(client, n) \ -device_create_file(&client->dev, &dev_attr_cpu##n##_vid) - -#define sysfs_in(n) \ -sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ -sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ -sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ - -#define device_create_file_in(client, n) \ -({device_create_file(&client->dev, &dev_attr_in##n##_input); \ -device_create_file(&client->dev, &dev_attr_in##n##_min); \ -device_create_file(&client->dev, &dev_attr_in##n##_max);}) - -#define sysfs_fan(n) \ -sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ -sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ -sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) - -#define device_create_file_fan(client, n) \ -({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ -device_create_file(&client->dev, &dev_attr_fan##n##_min); \ -device_create_file(&client->dev, &dev_attr_fan##n##_div);}) - -#define sysfs_fan_off(n) \ -sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ - -#define device_create_file_fan_off(client, n) \ -device_create_file(&client->dev, &dev_attr_fan##n##_off) - -#define sysfs_temp(n) \ -sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ -sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ -sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) - -#define device_create_file_temp(client, n) \ -({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) - -#define sysfs_alarms() \ -sysfs_ro(alarms, , GL520_REG_ALARMS) \ -sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ -sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) - -#define device_create_file_alarms(client) \ -({device_create_file(&client->dev, &dev_attr_alarms); \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask);}) - - -sysfs_vid(0) - -sysfs_in(0) -sysfs_in(1) -sysfs_in(2) -sysfs_in(3) -sysfs_in(4) - -sysfs_fan(1) -sysfs_fan(2) -sysfs_fan_off(1) - -sysfs_temp(1) -sysfs_temp(2) - -sysfs_alarms() - - -static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} - -#define VDD_FROM_REG(val) (((val)*95+2)/4) -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) - -#define IN_FROM_REG(val) ((val)*19) -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) - -static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_input[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_min[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_max[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - u8 r; - - down(&data->update_lock); - - if (n == 0) - r = VDD_TO_REG(v); - else - r = IN_TO_REG(v); - - data->in_min[n] = r; - - if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); - else - gl520_write_value(client, reg, r); - - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - u8 r; - - if (n == 0) - r = VDD_TO_REG(v); - else - r = IN_TO_REG(v); - - down(&data->update_lock); - - data->in_max[n] = r; - - if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); - else - gl520_write_value(client, reg, r); - - up(&data->update_lock); - return count; -} - -#define DIV_FROM_REG(val) (1 << (val)) -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) -#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); - -static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); -} - -static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); -} - -static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); -} - -static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->fan_off); -} - -static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - u8 r; - - down(&data->update_lock); - r = FAN_TO_REG(v, data->fan_div[n - 1]); - data->fan_min[n - 1] = r; - - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); - else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); - - data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - if (data->fan_min[n - 1] == 0) - data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; - else - data->alarm_mask |= (n == 1) ? 0x20 : 0x40; - data->beep_mask &= data->alarm_mask; - gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - u8 r; - - switch (v) { - case 1: r = 0; break; - case 2: r = 1; break; - case 4: r = 2; break; - case 8: r = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - data->fan_div[n - 1] = r; - - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); - else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10)?1:0; - - down(&data->update_lock); - data->fan_off = r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); - up(&data->update_lock); - return count; -} - -#define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) - -static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); -} - -static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); -} - -static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); -} - -static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[n - 1] = TEMP_TO_REG(v);; - gl520_write_value(client, reg, data->temp_max[n - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->alarms); -} - -static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->beep_enable); -} - -static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->beep_mask); -} - -static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10)?0:1; - - down(&data->update_lock); - data->beep_enable = !r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); - up(&data->update_lock); - return count; -} - -static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - r &= data->alarm_mask; - data->beep_mask = r; - gl520_write_value(client, reg, r); - up(&data->update_lock); - return count; -} - - -/* - * Real code - */ - -static int gl520_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, gl520_detect); -} - -static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct gl520_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl520_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct gl520_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; - - /* Determine the chip type. */ - if (kind < 0) { - if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || - ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || - ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { - dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); - goto exit_free; - } - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the GL520SM chip */ - gl520_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file_vid(new_client, 0); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - if (!data->two_temps) - device_create_file_in(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan_off(new_client, 1); - - device_create_file_temp(new_client, 1); - if (data->two_temps) - device_create_file_temp(new_client, 2); - - device_create_file_alarms(new_client); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - - -/* Called when we have found a new GL520SM. */ -static void gl520_init_client(struct i2c_client *client) -{ - struct gl520_data *data = i2c_get_clientdata(client); - u8 oldconf, conf; - - conf = oldconf = gl520_read_value(client, GL520_REG_CONF); - - data->alarm_mask = 0xff; - data->vrm = i2c_which_vrm(); - - if (extra_sensor_type == 1) - conf &= ~0x10; - else if (extra_sensor_type == 2) - conf |= 0x10; - data->two_temps = !(conf & 0x10); - - /* If IRQ# is disabled, we can safely force comparator mode */ - if (!(conf & 0x20)) - conf &= 0xf7; - - /* Enable monitoring if needed */ - conf |= 0x40; - - if (conf != oldconf) - gl520_write_value(client, GL520_REG_CONF, conf); - - gl520_update_device(&(client->dev)); - - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - - data->beep_mask &= data->alarm_mask; - gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); -} - -static int gl520_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention */ -static int gl520_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - - -static struct gl520_data *gl520_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl520_data *data = i2c_get_clientdata(client); - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - - dev_dbg(&client->dev, "Starting gl520sm update\n"); - - data->alarms = gl520_read_value(client, GL520_REG_ALARMS); - data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; - - val = gl520_read_value(client, GL520_REG_IN0_LIMIT); - data->in_min[0] = val & 0xff; - data->in_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN1_LIMIT); - data->in_min[1] = val & 0xff; - data->in_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN2_LIMIT); - data->in_min[2] = val & 0xff; - data->in_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN3_LIMIT); - data->in_min[3] = val & 0xff; - data->in_max[3] = (val >> 8) & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_INPUT); - data->fan_input[0] = (val >> 8) & 0xff; - data->fan_input[1] = val & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_MIN); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); - data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); - data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); - - val = gl520_read_value(client, GL520_REG_FAN_DIV); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - data->fan_off = (val >> 2) & 0x01; - - data->alarms &= data->alarm_mask; - - val = gl520_read_value(client, GL520_REG_CONF); - data->beep_enable = !((val >> 2) & 1); - - data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); - data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); - data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); - data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); - - /* Temp1 and Vin4 are the same input */ - if (data->two_temps) { - data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); - data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); - data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); - } else { - data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); - data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); - data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - - -static int __init sensors_gl520sm_init(void) -{ - return i2c_add_driver(&gl520_driver); -} - -static void __exit sensors_gl520sm_exit(void) -{ - i2c_del_driver(&gl520_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard , " - "Kyösti Mälkki , " - "Maarten Deprez "); -MODULE_DESCRIPTION("GL520SM driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_gl520sm_init); -module_exit(sensors_gl520sm_exit); diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c deleted file mode 100644 index db20c9e4739..00000000000 --- a/drivers/i2c/chips/it87.c +++ /dev/null @@ -1,1184 +0,0 @@ -/* - it87.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring. - - 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 - Largely inspired by lm78.c of the same package - - 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. -*/ - -/* - djg@pdp8.net David Gesswein 7/18/01 - Modified to fix bug with not all alarms enabled. - Added ability to read battery voltage and select temperature sensor - type at module load time. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -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 */ -SENSORS_INSMOD_2(it87, it8712); - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x04 /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ -#define DEVREV 0x22 /* Register: Device Revision */ - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static int superio_inw(int reg) -{ - int val; - outb(reg++, REG); - val = inb(VAL) << 8; - outb(reg, REG); - val |= inb(VAL); - return val; -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x01, REG); - outb(0x55, REG); - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -#define IT8712F_DEVID 0x8712 -#define IT8705F_DEVID 0x8705 -#define IT87_ACT_REG 0x30 -#define IT87_BASE_REG 0x60 - -/* 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; - -/* Many IT87 constants specified below */ - -/* Length of ISA address segment */ -#define IT87_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define IT87_ADDR_REG_OFFSET 5 -#define IT87_DATA_REG_OFFSET 6 - -/*----- The IT87 registers -----*/ - -#define IT87_REG_CONFIG 0x00 - -#define IT87_REG_ALARM1 0x01 -#define IT87_REG_ALARM2 0x02 -#define IT87_REG_ALARM3 0x03 - -#define IT87_REG_VID 0x0a -#define IT87_REG_FAN_DIV 0x0b - -/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ - -#define IT87_REG_FAN(nr) (0x0d + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) -#define IT87_REG_FAN_MAIN_CTRL 0x13 -#define IT87_REG_FAN_CTL 0x14 -#define IT87_REG_PWM(nr) (0x15 + (nr)) - -#define IT87_REG_VIN(nr) (0x20 + (nr)) -#define IT87_REG_TEMP(nr) (0x29 + (nr)) - -#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) -#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) -#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) - -#define IT87_REG_I2C_ADDR 0x48 - -#define IT87_REG_VIN_ENABLE 0x50 -#define IT87_REG_TEMP_ENABLE 0x51 - -#define IT87_REG_CHIPID 0x58 - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ - ((val)+500)/1000),-128,127)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) - -#define PWM_TO_REG(val) ((val) >> 1) -#define PWM_FROM_REG(val) (((val)&0x7f) << 1) - -static int DIV_TO_REG(int val) -{ - int answer = 0; - while ((val >>= 1) != 0) - answer++; - return answer; -} -#define DIV_FROM_REG(val) (1 << (val)) - - -/* For each registered IT87, we need to keep some data in memory. That - data is pointed to by it87_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new it87 client is - allocated. */ -struct it87_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp[3]; /* Register value */ - u8 temp_high[3]; /* Register value */ - u8 temp_low[3]; /* Register value */ - u8 sensor; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - int vrm; - u32 alarms; /* Register encoding, combined */ - u8 fan_main_ctrl; /* Register value */ - u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ -}; - - -static int it87_attach_adapter(struct i2c_adapter *adapter); -static int it87_find(int *address); -static int it87_detect(struct i2c_adapter *adapter, int address, int kind); -static int it87_detach_client(struct i2c_client *client); - -static int it87_read_value(struct i2c_client *client, u8 register); -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); - - -static struct i2c_driver it87_driver = { - .owner = THIS_MODULE, - .name = "it87", - .id = I2C_DRIVERID_IT87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = it87_attach_adapter, - .detach_client = it87_detach_client, -}; - -static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - it87_write_value(client, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - it87_write_value(client, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in, NULL, offset); - -#define limit_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - -show_in_offset(0); -limit_in_offset(0); -show_in_offset(1); -limit_in_offset(1); -show_in_offset(2); -limit_in_offset(2); -show_in_offset(3); -limit_in_offset(3); -show_in_offset(4); -limit_in_offset(4); -show_in_offset(5); -limit_in_offset(5); -show_in_offset(6); -limit_in_offset(6); -show_in_offset(7); -limit_in_offset(7); -show_in_offset(8); - -/* 3 temperatures */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); -} -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - u8 reg = data->sensor; /* In case the value is updated while we use it */ - - if (reg & (1 << nr)) - return sprintf(buf, "3\n"); /* thermal diode */ - if (reg & (8 << nr)) - return sprintf(buf, "2\n"); /* thermistor */ - return sprintf(buf, "0\n"); /* disabled */ -} -static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - - data->sensor &= ~(1 << nr); - data->sensor &= ~(8 << nr); - /* 3 = thermal diode; 2 = thermistor; 0 = disabled */ - if (val == 3) - data->sensor |= 1 << nr; - else if (val == 2) - data->sensor |= 8 << nr; - else if (val != 0) { - up(&data->update_lock); - return -EINVAL; - } - it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); - up(&data->update_lock); - return count; -} -#define show_sensor_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor, set_sensor, offset - 1); - -show_sensor_offset(1); -show_sensor_offset(2); -show_sensor_offset(3); - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", - FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} -static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); -} -static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); -} -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int i, min[3]; - u8 old; - - down(&data->update_lock); - old = it87_read_value(client, IT87_REG_FAN_DIV); - - for (i = 0; i < 3; i++) - min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); - - switch (nr) { - case 0: - case 1: - data->fan_div[nr] = DIV_TO_REG(val); - break; - case 2: - if (val < 8) - data->fan_div[nr] = 1; - else - data->fan_div[nr] = 3; - } - val = old & 0x80; - val |= (data->fan_div[0] & 0x07); - val |= (data->fan_div[1] & 0x07) << 3; - if (data->fan_div[2] == 3) - val |= 0x1 << 6; - it87_write_value(client, IT87_REG_FAN_DIV, val); - - for (i = 0; i < 3; i++) { - data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); - it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); - } - up(&data->update_lock); - return count; -} -static ssize_t set_pwm_enable(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - - if (val == 0) { - int tmp; - /* make sure the fan is on when in on/off mode */ - tmp = it87_read_value(client, IT87_REG_FAN_CTL); - it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr)); - /* set on/off mode */ - data->fan_main_ctrl &= ~(1 << nr); - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - } else if (val == 1) { - /* set SmartGuardian mode */ - data->fan_main_ctrl |= (1 << nr); - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - /* set saved pwm value, clear FAN_CTLX PWM mode bit */ - it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); - } else { - up(&data->update_lock); - return -EINVAL; - } - - up(&data->update_lock); - return count; -} -static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - if (val < 0 || val > 255) - return -EINVAL; - - down(&data->update_lock); - data->manual_pwm_ctl[nr] = val; - if (data->fan_main_ctrl & (1 << nr)) - it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -#define show_pwm_offset(offset) \ -static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm_enable, set_pwm_enable, offset - 1); \ -static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, offset - 1); - -show_pwm_offset(1); -show_pwm_offset(2); -show_pwm_offset(3); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -/* This function is called when: - * it87_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and it87_driver is still present) */ -static int it87_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, it87_detect); -} - -/* SuperIO detection - will change normal_isa[0] if a chip is found */ -static int it87_find(int *address) -{ - int err = -ENODEV; - - superio_enter(); - chip_type = superio_inw(DEVID); - if (chip_type != IT8712F_DEVID - && chip_type != IT8705F_DEVID) - goto exit; - - superio_select(); - if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - pr_info("it87: Device not activated, skipping\n"); - goto exit; - } - - *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); - if (*address == 0) { - pr_info("it87: Base address not set, skipping\n"); - goto exit; - } - - err = 0; - pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", - chip_type, *address, superio_inb(DEVREV) & 0x0f); - -exit: - superio_exit(); - return err; -} - -/* This function is called by i2c_detect */ -int it87_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct it87_data *data; - int err = 0; - const char *name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - int enable_pwm_interface; - - if (!is_isa && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* Reserve the ISA region */ - if (is_isa) - if (!request_region(address, IT87_EXTENT, it87_driver.name)) - goto ERROR0; - - /* Probe whether there is anything available on this address. Already - done for SMBus and Super-I/O clients */ - if (kind < 0) { - if (is_isa && !chip_type) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* 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 it87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct it87_data)); - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &it87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) - || (!is_isa - && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) { - err = -ENODEV; - goto ERROR2; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = it87_read_value(new_client, IT87_REG_CHIPID); - if (i == 0x90) { - kind = it87; - if ((is_isa) && (chip_type == IT8712F_DEVID)) - kind = it8712; - } - else { - if (kind == 0) - dev_info(&adapter->dev, - "Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR2; - } - } - - if (kind == it87) { - name = "it87"; - } else if (kind == it8712) { - name = "it8712"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->type = kind; - 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 ERROR2; - - /* Check PWM configuration */ - enable_pwm_interface = it87_check_pwm(new_client); - - /* Initialize the IT87 chip */ - it87_init_client(new_client, data); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - if (enable_pwm_interface) { - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); - } - - if (data->type == it8712) { - data->vrm = i2c_which_vrm(); - device_create_file_vrm(new_client); - device_create_file_vid(new_client); - } - - return 0; - -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, IT87_EXTENT); -ERROR0: - return err; -} - -static int it87_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, IT87_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ -static int it87_read_value(struct i2c_client *client, u8 reg) -{ - struct it87_data *data = i2c_get_clientdata(client); - - int res; - if (i2c_is_isa_client(client)) { - down(&data->lock); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - res = inb_p(client->addr + IT87_DATA_REG_OFFSET); - up(&data->lock); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ -static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - struct it87_data *data = i2c_get_clientdata(client); - - if (i2c_is_isa_client(client)) { - down(&data->lock); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - outb_p(value, client->addr + IT87_DATA_REG_OFFSET); - up(&data->lock); - return 0; - } else - 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) -{ - int tmp, i; - - /* initialize to sane defaults: - * - if the chip is in manual pwm mode, this will be overwritten with - * the actual settings on the chip (so in this case, initialization - * is not needed) - * - if in automatic or on/off mode, we could switch to manual mode, - * read the registers and set manual_pwm_ctl accordingly, but currently - * this is not implemented, so we initialize to something sane */ - for (i = 0; i < 3; i++) { - data->manual_pwm_ctl[i] = 0xff; - } - - /* Check if temperature channnels are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - if ((tmp & 0x3f) == 0) { - /* Temp1,Temp3=thermistor; Temp2=thermal diode */ - tmp = (tmp & 0xc0) | 0x2a; - it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); - } - data->sensor = tmp; - - /* Check if voltage monitors are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); - if ((tmp & 0xff) == 0) { - /* Enable all voltage monitors */ - it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); - } - - /* Check if tachometers are reset manually or by some reason */ - data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); - if ((data->fan_main_ctrl & 0x70) == 0) { - /* Enable all fan tachometers */ - data->fan_main_ctrl |= 0x70; - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - } - - /* Set current fan mode registers and the default settings for the - * other mode registers */ - for (i = 0; i < 3; i++) { - if (data->fan_main_ctrl & (1 << i)) { - /* pwm mode */ - tmp = it87_read_value(client, IT87_REG_PWM(i)); - if (tmp & 0x80) { - /* automatic pwm - not yet implemented, but - * leave the settings made by the BIOS alone - * until a change is requested via the sysfs - * interface */ - } else { - /* manual pwm */ - data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp); - } - } - } - - /* Start monitoring */ - it87_write_value(client, IT87_REG_CONFIG, - (it87_read_value(client, IT87_REG_CONFIG) & 0x36) - | (update_vbat ? 0x41 : 0x01)); -} - -static struct it87_data *it87_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ - it87_write_value(client, IT87_REG_CONFIG, - it87_read_value(client, IT87_REG_CONFIG) | 0x40); - } - for (i = 0; i <= 7; i++) { - data->in[i] = - it87_read_value(client, IT87_REG_VIN(i)); - data->in_min[i] = - it87_read_value(client, IT87_REG_VIN_MIN(i)); - data->in_max[i] = - it87_read_value(client, IT87_REG_VIN_MAX(i)); - } - data->in[8] = - it87_read_value(client, IT87_REG_VIN(8)); - /* Temperature sensor doesn't have limit registers, set - to min and max value */ - data->in_min[8] = 0; - data->in_max[8] = 255; - - for (i = 0; i < 3; i++) { - data->fan[i] = - it87_read_value(client, IT87_REG_FAN(i)); - data->fan_min[i] = - it87_read_value(client, IT87_REG_FAN_MIN(i)); - } - for (i = 0; i < 3; i++) { - data->temp[i] = - it87_read_value(client, IT87_REG_TEMP(i)); - data->temp_high[i] = - it87_read_value(client, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i] = - it87_read_value(client, IT87_REG_TEMP_LOW(i)); - } - - i = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[0] = i & 0x07; - data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = (i & 0x40) ? 3 : 1; - - data->alarms = - it87_read_value(client, IT87_REG_ALARM1) | - (it87_read_value(client, IT87_REG_ALARM2) << 8) | - (it87_read_value(client, IT87_REG_ALARM3) << 16); - data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); - - data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); - /* The 8705 does not have VID capability */ - if (data->type == it8712) { - data->vid = it87_read_value(client, IT87_REG_VID); - data->vid &= 0x1f; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sm_it87_init(void) -{ - int addr; - - if (!it87_find(&addr)) { - normal_isa[0] = addr; - } - return i2c_add_driver(&it87_driver); -} - -static void __exit sm_it87_exit(void) -{ - i2c_del_driver(&it87_driver); -} - - -MODULE_AUTHOR("Chris Gauthron "); -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); -module_exit(sm_it87_exit); diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c deleted file mode 100644 index 7c6f9ea5a25..00000000000 --- a/drivers/i2c/chips/lm63.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * lm63.c - driver for the National Semiconductor LM63 temperature sensor - * with integrated fan control - * Copyright (C) 2004-2005 Jean Delvare - * Based on the lm90 driver. - * - * The LM63 is a sensor chip made by National Semiconductor. It measures - * two temperatures (its own and one external one) and the speed of one - * fan, those speed it can additionally control. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM63.html - * - * The LM63 is basically an LM86 with fan speed monitoring and control - * capabilities added. It misses some of the LM86 features though: - * - No low limit for local temperature. - * - No critical limit for local temperature. - * - Critical limit for remote temperature can be changed only once. We - * will consider that the critical limit is read-only. - * - * The datasheet isn't very clear about what the tachometer reading is. - * I had a explanation from National Semiconductor though. The two lower - * bits of the read value have to be masked out. The value is still 16 bit - * in width. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm63); - -/* - * The LM63 registers - */ - -#define LM63_REG_CONFIG1 0x03 -#define LM63_REG_CONFIG2 0xBF -#define LM63_REG_CONFIG_FAN 0x4A - -#define LM63_REG_TACH_COUNT_MSB 0x47 -#define LM63_REG_TACH_COUNT_LSB 0x46 -#define LM63_REG_TACH_LIMIT_MSB 0x49 -#define LM63_REG_TACH_LIMIT_LSB 0x48 - -#define LM63_REG_PWM_VALUE 0x4C -#define LM63_REG_PWM_FREQ 0x4D - -#define LM63_REG_LOCAL_TEMP 0x00 -#define LM63_REG_LOCAL_HIGH 0x05 - -#define LM63_REG_REMOTE_TEMP_MSB 0x01 -#define LM63_REG_REMOTE_TEMP_LSB 0x10 -#define LM63_REG_REMOTE_OFFSET_MSB 0x11 -#define LM63_REG_REMOTE_OFFSET_LSB 0x12 -#define LM63_REG_REMOTE_HIGH_MSB 0x07 -#define LM63_REG_REMOTE_HIGH_LSB 0x13 -#define LM63_REG_REMOTE_LOW_MSB 0x08 -#define LM63_REG_REMOTE_LOW_LSB 0x14 -#define LM63_REG_REMOTE_TCRIT 0x19 -#define LM63_REG_REMOTE_TCRIT_HYST 0x21 - -#define LM63_REG_ALERT_STATUS 0x02 -#define LM63_REG_ALERT_MASK 0x16 - -#define LM63_REG_MAN_ID 0xFE -#define LM63_REG_CHIP_ID 0xFF - -/* - * Conversions and various macros - * For tachometer counts, the LM63 uses 16-bit values. - * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ - 5400000 / (reg)) -#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \ - (5400000 / (val)) & 0xFFFC) -#define TEMP8_FROM_REG(reg) ((reg) * 1000) -#define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) -#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) -#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 127000 ? 127 : \ - ((val) + 500) / 1000) - -/* - * Functions declaration - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter); -static int lm63_detach_client(struct i2c_client *client); - -static struct lm63_data *lm63_update_device(struct device *dev); - -static int lm63_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm63_init_client(struct i2c_client *client); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm63_driver = { - .owner = THIS_MODULE, - .name = "lm63", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm63_attach_adapter, - .detach_client = lm63_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm63_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 config, config_fan; - u16 fan[2]; /* 0: input - 1: low limit */ - u8 pwm1_freq; - u8 pwm1_value; - s8 temp8[3]; /* 0: local input - 1: local high limit - 2: remote critical limit */ - s16 temp11[3]; /* 0: remote input - 1: remote low limit - 2: remote high limit */ - u8 temp2_crit_hyst; - u8 alarms; -}; - -/* - * Sysfs callback functions and files - */ - -static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); -} - -static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan[1] = FAN_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, - data->fan[1] & 0xFF); - i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, - data->fan[1] >> 8); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? - 255 : (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq)); -} - -static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val; - - if (!(data->config_fan & 0x20)) /* register is read-only */ - return -EPERM; - - val = simple_strtoul(buf, NULL, 10); - down(&data->update_lock); - data->pwm1_value = val <= 0 ? 0 : - val >= 255 ? 2 * data->pwm1_freq : - (val * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); -} - -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); -} - -static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp8[1] = TEMP8_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); -} - -static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM63_REG_REMOTE_LOW_MSB, - LM63_REG_REMOTE_LOW_LSB, - LM63_REG_REMOTE_HIGH_MSB, - LM63_REG_REMOTE_HIGH_LSB, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - data->temp11[nr] = TEMP11_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], - data->temp11[nr] >> 8); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], - data->temp11[nr] & 0xff); - up(&data->update_lock); - return count; -} - -/* Hysteresis register holds a relative value, while we want to present - an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) - - TEMP8_FROM_REG(data->temp2_crit_hyst)); -} - -/* And now the other way around, user-space provides an absolute - hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - long hyst; - - down(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp8[2]) - val; - i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, - HYST_TO_REG(hyst)); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); -static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, - set_fan, 1); - -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); -static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); - -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 1); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 2); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, - set_temp2_crit_hyst); - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm63_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm63_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm63_data)); - - /* The common I2C client data is placed right before the - LM63-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm63_driver; - new_client->flags = 0; - - /* Default to an LM63 if forced */ - if (kind == 0) - kind = lm63; - - if (kind < 0) { /* must identify */ - u8 man_id, chip_id, reg_config1, reg_config2; - u8 reg_alert_status, reg_alert_mask; - - man_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG1); - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG2); - reg_alert_status = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_STATUS); - reg_alert_mask = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_MASK); - - if (man_id == 0x01 /* National Semiconductor */ - && chip_id == 0x41 /* LM63 */ - && (reg_config1 & 0x18) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && (reg_alert_status & 0x20) == 0x00 - && (reg_alert_mask & 0xA4) == 0xA4) { - kind = lm63; - } else { /* failed */ - dev_dbg(&adapter->dev, "Unsupported chip " - "(man_id=0x%02X, chip_id=0x%02X).\n", - man_id, chip_id); - goto exit_free; - } - } - - strlcpy(new_client->name, "lm63", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM63 chip */ - lm63_init_client(new_client); - - /* Register sysfs hooks */ - if (data->config & 0x04) { /* tachometer enabled */ - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - } - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ -static void lm63_init_client(struct i2c_client *client) -{ - struct lm63_data *data = i2c_get_clientdata(client); - - data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); - data->config_fan = i2c_smbus_read_byte_data(client, - LM63_REG_CONFIG_FAN); - - /* Start converting if needed */ - if (data->config & 0x40) { /* standby */ - dev_dbg(&client->dev, "Switching to operational mode"); - data->config &= 0xA7; - i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, - data->config); - } - - /* We may need pwm1_freq before ever updating the client data */ - data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - - /* Show some debug info about the LM63 configuration */ - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); - dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", - (data->config_fan & 0x08) ? "1.4" : "360", - ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); - dev_dbg(&client->dev, "PWM output active %s, %s mode\n", - (data->config_fan & 0x10) ? "low" : "high", - (data->config_fan & 0x20) ? "manual" : "auto"); -} - -static int lm63_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 struct lm63_data *lm63_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - if (data->config & 0x04) { /* tachometer enabled */ - /* order matters for fan1_input */ - data->fan[0] = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan[0] |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan[1] = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); - } - - data->pwm1_freq = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); - - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); - - /* order matters for temp2_input */ - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp11[0] |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_LSB); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); - data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST); - - data->alarms = i2c_smbus_read_byte_data(client, - LM63_REG_ALERT_STATUS) & 0x7F; - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm63_init(void) -{ - return i2c_add_driver(&lm63_driver); -} - -static void __exit sensors_lm63_exit(void) -{ - i2c_del_driver(&lm63_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM63 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm63_init); -module_exit(sensors_lm63_exit); diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c deleted file mode 100644 index 5be164ed278..00000000000 --- a/drivers/i2c/chips/lm75.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm75); - -/* Many LM75 constants specified below */ - -/* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 - -/* Each client has this additional data */ -struct lm75_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - u16 temp_input; /* Register values */ - u16 temp_max; - u16 temp_hyst; -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct lm75_data *lm75_update_device(struct device *dev); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .owner = THIS_MODULE, - .name = "lm75", - .id = I2C_DRIVERID_LM75, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm75_data *data = lm75_update_device(dev); \ - return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ -} -show(temp_max); -show(temp_hyst); -show(temp_input); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm75_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = LM75_TEMP_TO_REG(temp); \ - lm75_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set(temp_max, LM75_REG_TEMP_OS); -set(temp_hyst, LM75_REG_TEMP_HYST); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); - -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm75_detect); -} - -/* This function is called by i2c_detect */ -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm75_data *data; - int err = 0; - const char *name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - dev_dbg(&adapter->dev, - "lm75_detect called for an ISA bus adapter?!?\n"); - goto exit; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm75_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. There is no identification- - dedicated register so we have to rely on several tricks: - unused bits, registers cycling over 8-address boundaries, - addresses 0x04-0x07 returning the last read value. - The cycling+unused addresses combination is not tested, - since it would significantly slow the detection down and would - hardly add any value. */ - if (kind < 0) { - int cur, conf, hyst, os; - - /* Unused addresses */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - goto exit_free; - - /* Unused bits */ - if (conf & 0xe0) - goto exit_free; - - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto exit_free; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; - - if (kind == lm75) { - name = "lm75"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM75 chip */ - lm75_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm75_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm75_init_client(struct i2c_client *client) -{ - /* Initialize the LM75 chip */ - lm75_write_value(client, LM75_REG_CONF, 0); -} - -static struct lm75_data *lm75_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm75 update\n"); - - data->temp_input = lm75_read_value(client, LM75_REG_TEMP); - data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm75_init(void) -{ - return i2c_add_driver(&lm75_driver); -} - -static void __exit sensors_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM75 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm75_init); -module_exit(sensors_lm75_exit); diff --git a/drivers/i2c/chips/lm75.h b/drivers/i2c/chips/lm75.h deleted file mode 100644 index 63e3f2fb4c2..00000000000 --- a/drivers/i2c/chips/lm75.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - lm75.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Mark M. Hoffman - - 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. -*/ - -/* - This file contains common code for encoding/decoding LM75 type - temperature readings, which are emulated by many of the chips - we support. As the user is unlikely to load more than one driver - which contains this code, we don't worry about the wasted space. -*/ - -#include - -/* straight from the datasheet */ -#define LM75_TEMP_MIN (-55000) -#define LM75_TEMP_MAX 125000 - -/* TEMP: 0.001C/bit (-55C to +125C) - REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); - ntemp += (ntemp<0 ? -250 : 250); - return (u16)((ntemp / 500) << 7); -} - -static inline int LM75_TEMP_FROM_REG(u16 reg) -{ - /* use integer division instead of equivalent right shift to - guarantee arithmetic shift and preserve the sign */ - return ((s16)reg / 128) * 500; -} - diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c deleted file mode 100644 index b98f4495299..00000000000 --- a/drivers/i2c/chips/lm77.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - lm77.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2004 Andras BALI - - Heavily based on lm75.c by Frodo Looijaard . The LM77 - is a temperature sensor and thermal window comparator with 0.5 deg - resolution made by National Semiconductor. Complete datasheet can be - obtained at their site: - http://www.national.com/pf/LM/LM77.html - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm77); - -/* The LM77 registers */ -#define LM77_REG_TEMP 0x00 -#define LM77_REG_CONF 0x01 -#define LM77_REG_TEMP_HYST 0x02 -#define LM77_REG_TEMP_CRIT 0x03 -#define LM77_REG_TEMP_MIN 0x04 -#define LM77_REG_TEMP_MAX 0x05 - -/* Each client has this additional data */ -struct lm77_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; - unsigned long last_updated; /* In jiffies */ - int temp_input; /* Temperatures */ - int temp_crit; - int temp_min; - int temp_max; - int temp_hyst; - u8 alarms; -}; - -static int lm77_attach_adapter(struct i2c_adapter *adapter); -static int lm77_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm77_init_client(struct i2c_client *client); -static int lm77_detach_client(struct i2c_client *client); -static u16 lm77_read_value(struct i2c_client *client, u8 reg); -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); - -static struct lm77_data *lm77_update_device(struct device *dev); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm77_driver = { - .owner = THIS_MODULE, - .name = "lm77", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm77_attach_adapter, - .detach_client = lm77_detach_client, -}; - -/* straight from the datasheet */ -#define LM77_TEMP_MIN (-55000) -#define LM77_TEMP_MAX 125000 - -/* In the temperature registers, the low 3 bits are not part of the - temperature values; they are the status bits. */ -static inline u16 LM77_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); - return (u16)((ntemp / 500) * 8); -} - -static inline int LM77_TEMP_FROM_REG(u16 reg) -{ - return ((int)reg / 8) * 500; -} - -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm77_data *data = lm77_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ -} - -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); -show(alarms); - -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); -} -static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); -} -static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); -} - -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - up(&data->update_lock); \ - return count; \ -} - -set(temp_min, LM77_REG_TEMP_MIN); -set(temp_max, LM77_REG_TEMP_MAX); - -/* hysteresis is stored as a relative value on the chip, so it has to be - converted first */ -static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = data->temp_crit - val; - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); - up(&data->update_lock); - return count; -} - -/* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - long val = simple_strtoul(buf, NULL, 10); - int oldcrithyst; - - down(&data->update_lock); - oldcrithyst = data->temp_crit - data->temp_hyst; - data->temp_crit = val; - data->temp_hyst = data->temp_crit - oldcrithyst; - lm77_write_value(client, LM77_REG_TEMP_CRIT, - LM77_TEMP_TO_REG(data->temp_crit)); - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_max, set_temp_max); - -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, - show_temp_min_hyst, NULL); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); - -static DEVICE_ATTR(alarms, S_IRUGO, - show_alarms, NULL); - -static int lm77_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm77_detect); -} - -/* This function is called by i2c_detect */ -static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm77_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm77_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm77_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm77_driver; - new_client->flags = 0; - - /* Here comes the remaining detection. Since the LM77 has no - register dedicated to identification, we have to rely on the - following tricks: - - 1. the high 4 bits represent the sign and thus they should - always be the same - 2. the high 3 bits are unused in the configuration register - 3. addresses 0x06 and 0x07 return the last read value - 4. registers cycling over 8-address boundaries - - Word-sized registers are high-byte first. */ - if (kind < 0) { - int i, cur, conf, hyst, crit, min, max; - - /* addresses cycling */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - crit = i2c_smbus_read_word_data(new_client, 3); - min = i2c_smbus_read_word_data(new_client, 4); - max = i2c_smbus_read_word_data(new_client, 5); - for (i = 8; i <= 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != crit - || i2c_smbus_read_word_data(new_client, i + 4) != min - || i2c_smbus_read_word_data(new_client, i + 5) != max) - goto exit_free; - - /* sign bits */ - if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0) - || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0) - || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0) - || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0) - || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0)) - goto exit_free; - - /* unused bits */ - if (conf & 0xe0) - goto exit_free; - - /* 0x06 and 0x07 return the last read value */ - cur = i2c_smbus_read_word_data(new_client, 0); - if (i2c_smbus_read_word_data(new_client, 6) != cur - || i2c_smbus_read_word_data(new_client, 7) != cur) - goto exit_free; - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; - min = i2c_smbus_read_word_data(new_client, 4); - if (i2c_smbus_read_word_data(new_client, 6) != min - || i2c_smbus_read_word_data(new_client, 7) != min) - goto exit_free; - - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm77; - - if (kind == lm77) { - name = "lm77"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM77 chip */ - lm77_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm77_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - The LM77 uses the high-byte first convention. */ -static u16 lm77_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm77_init_client(struct i2c_client *client) -{ - /* Initialize the LM77 chip - turn off shutdown mode */ - int conf = lm77_read_value(client, LM77_REG_CONF); - if (conf & 1) - lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); -} - -static struct lm77_data *lm77_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); - data->alarms = - lm77_read_value(client, LM77_REG_TEMP) & 0x0007; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm77_init(void) -{ - return i2c_add_driver(&lm77_driver); -} - -static void __exit sensors_lm77_exit(void) -{ - i2c_del_driver(&lm77_driver); -} - -MODULE_AUTHOR("Andras BALI "); -MODULE_DESCRIPTION("LM77 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm77_init); -module_exit(sensors_lm77_exit); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c deleted file mode 100644 index 29241469dcb..00000000000 --- a/drivers/i2c/chips/lm78.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* 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 int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(lm78, lm78j, lm79); - -/* Many LM78 constants specified below */ - -/* Length of ISA address segment */ -#define LM78_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define LM78_ADDR_REG_OFFSET 5 -#define LM78_DATA_REG_OFFSET 6 - -/* The LM78 registers */ -#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define LM78_REG_IN(nr) (0x20 + (nr)) - -#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) -#define LM78_REG_FAN(nr) (0x28 + (nr)) - -#define LM78_REG_TEMP 0x27 -#define LM78_REG_TEMP_OVER 0x39 -#define LM78_REG_TEMP_HYST 0x3a - -#define LM78_REG_ALARM1 0x41 -#define LM78_REG_ALARM2 0x42 - -#define LM78_REG_VID_FANDIV 0x47 - -#define LM78_REG_CONFIG 0x40 -#define LM78_REG_CHIPID 0x49 -#define LM78_REG_I2C_ADDR 0x48 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. */ - -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ -static inline u8 IN_TO_REG(unsigned long val) -{ - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); - return (nval + 8) / 16; -} -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static inline int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* TEMP: mC (-128C to +127C) - REG: 1C/bit, two's complement */ -static inline s8 TEMP_TO_REG(int val) -{ - int nval = SENSORS_LIMIT(val, -128000, 127000) ; - return nval<0 ? (nval-500)/1000 : (nval+500)/1000; -} - -static inline int TEMP_FROM_REG(s8 val) -{ - return val * 1000; -} - -/* VID: mV - REG: (see doc/vid) */ -static inline int VID_FROM_REG(u8 val) -{ - return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; -} - -#define DIV_FROM_REG(val) (1 << (val)) - -/* There are some complications in a module like this. First off, LM78 chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - LM78 chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the LM78 at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered LM78, we need to keep some data in memory. That - data is pointed to by lm78_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ -struct lm78_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); -static int lm78_detach_client(struct i2c_client *client); - -static int lm78_read_value(struct i2c_client *client, u8 register); -static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); -static struct lm78_data *lm78_update_device(struct device *dev); -static void lm78_init_client(struct i2c_client *client); - - -static struct i2c_driver lm78_driver = { - .owner = THIS_MODULE, - .name = "lm78", - .id = I2C_DRIVERID_LM78, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm78_attach_adapter, - .detach_client = lm78_detach_client, -}; - -/* 7 Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); -show_in_offset(6); - -/* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - unsigned long min; - u8 reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - reg = lm78_read_value(client, LM78_REG_VID_FANDIV); - switch (nr) { - case 0: - reg = (reg & 0xcf) | (data->fan_div[nr] << 4); - break; - case 1: - reg = (reg & 0x3f) | (data->fan_div[nr] << 6); - break; - } - lm78_write_value(client, LM78_REG_VID_FANDIV, reg); - - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 0) ; -} - -static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 1) ; -} - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -/* Fan 3 divisor is locked in H/W */ -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div); -static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div); -static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); - -/* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* This function is called when: - * lm78_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm78_driver is still present) */ -static int lm78_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm78_detect); -} - -/* This function is called by i2c_detect */ -int lm78_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i, err; - struct i2c_client *new_client; - struct lm78_data *data; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - err = -ENODEV; - goto ERROR0; - } - - /* Reserve the ISA region */ - if (is_isa) - if (!request_region(address, LM78_EXTENT, lm78_driver.name)) { - err = -EBUSY; - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 3) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct lm78_data)); - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm78_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { - err = -ENODEV; - goto ERROR2; - } - if (!is_isa && (lm78_read_value( - new_client, LM78_REG_I2C_ADDR) != address)) { - err = -ENODEV; - goto ERROR2; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = lm78_read_value(new_client, LM78_REG_CHIPID); - if (i == 0x00 || i == 0x20) - kind = lm78; - else if (i == 0x40) - kind = lm78j; - else if ((i & 0xfe) == 0xc0) - kind = lm79; - else { - if (kind == 0) - dev_warn(&adapter->dev, "Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR2; - } - } - - if (kind == lm78) { - client_name = "lm78"; - } else if (kind == lm78j) { - client_name = "lm78-j"; - } else if (kind == lm79) { - client_name = "lm79"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - - 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 ERROR2; - - /* Initialize the LM78 chip */ - lm78_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 3; i++) { - data->fan_min[i] = lm78_read_value(new_client, - LM78_REG_FAN_MIN(i)); - } - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan3_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - return 0; - -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, LM78_EXTENT); -ERROR0: - return err; -} - -static int lm78_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); - - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. */ -static int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - res = inb_p(client->addr + LM78_DATA_REG_OFFSET); - up(&data->lock); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - outb_p(value, client->addr + LM78_DATA_REG_OFFSET); - up(&data->lock); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM78. It should set limits, etc. */ -static void lm78_init_client(struct i2c_client *client) -{ - u8 config = lm78_read_value(client, LM78_REG_CONFIG); - - /* Start monitoring */ - if (!(config & 0x01)) - lm78_write_value(client, LM78_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static struct lm78_data *lm78_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting lm78 update\n"); - - for (i = 0; i <= 6; i++) { - data->in[i] = - lm78_read_value(client, LM78_REG_IN(i)); - data->in_min[i] = - lm78_read_value(client, LM78_REG_IN_MIN(i)); - data->in_max[i] = - lm78_read_value(client, LM78_REG_IN_MAX(i)); - } - for (i = 0; i < 3; i++) { - data->fan[i] = - lm78_read_value(client, LM78_REG_FAN(i)); - data->fan_min[i] = - lm78_read_value(client, LM78_REG_FAN_MIN(i)); - } - data->temp = lm78_read_value(client, LM78_REG_TEMP); - data->temp_over = - lm78_read_value(client, LM78_REG_TEMP_OVER); - data->temp_hyst = - lm78_read_value(client, LM78_REG_TEMP_HYST); - i = lm78_read_value(client, LM78_REG_VID_FANDIV); - data->vid = i & 0x0f; - if (data->type == lm79) - data->vid |= - (lm78_read_value(client, LM78_REG_CHIPID) & - 0x01) << 4; - else - data->vid |= 0x10; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + - (lm78_read_value(client, LM78_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - - data->fan_div[2] = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sm_lm78_init(void) -{ - return i2c_add_driver(&lm78_driver); -} - -static void __exit sm_lm78_exit(void) -{ - i2c_del_driver(&lm78_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm78_init); -module_exit(sm_lm78_exit); diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c deleted file mode 100644 index 8100595feb4..00000000000 --- a/drivers/i2c/chips/lm80.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * lm80.c - From lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 1998, 1999 Frodo Looijaard - * and Philip Edelbrock - * - * Ported to Linux 2.6 by Tiago Sousa - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm80); - -/* Many LM80 constants specified below */ - -/* The LM80 registers */ -#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) -#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) -#define LM80_REG_IN(nr) (0x20 + (nr)) - -#define LM80_REG_FAN1 0x28 -#define LM80_REG_FAN2 0x29 -#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) - -#define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_HOT_MAX 0x38 -#define LM80_REG_TEMP_HOT_HYST 0x39 -#define LM80_REG_TEMP_OS_MAX 0x3a -#define LM80_REG_TEMP_OS_HYST 0x3b - -#define LM80_REG_CONFIG 0x00 -#define LM80_REG_ALARM1 0x01 -#define LM80_REG_ALARM2 0x02 -#define LM80_REG_MASK1 0x03 -#define LM80_REG_MASK2 0x04 -#define LM80_REG_FANDIV 0x05 -#define LM80_REG_RES 0x06 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT(((val)+5)/10,0,255)) -#define IN_FROM_REG(val) ((val)*10) - -static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; - - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; - - return res / 10; -} - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val)<0?\ - ((val)-500)/1000:((val)+500)/1000,0,255) - -#define DIV_FROM_REG(val) (1 << (val)) - -/* - * Client data (each client gets its own) - */ - -struct lm80_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ -}; - -/* - * Functions declaration - */ - -static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm80_init_client(struct i2c_client *client); -static int lm80_detach_client(struct i2c_client *client); -static struct lm80_data *lm80_update_device(struct device *dev); -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm80_driver = { - .owner = THIS_MODULE, - .name = "lm80", - .id = I2C_DRIVERID_LM80, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm80_attach_adapter, - .detach_client = lm80_detach_client, -}; - -/* - * Sysfs stuff - */ - -#define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ -} -show_in(min0, in_min[0]); -show_in(min1, in_min[1]); -show_in(min2, in_min[2]); -show_in(min3, in_min[3]); -show_in(min4, in_min[4]); -show_in(min5, in_min[5]); -show_in(min6, in_min[6]); -show_in(max0, in_max[0]); -show_in(max1, in_max[1]); -show_in(max2, in_max[2]); -show_in(max3, in_max[3]); -show_in(max4, in_max[4]); -show_in(max5, in_max[5]); -show_in(max6, in_max[6]); -show_in(input0, in[0]); -show_in(input1, in[1]); -show_in(input2, in[2]); -show_in(input3, in[3]); -show_in(input4, in[4]); -show_in(input5, in[5]); -show_in(input6, in[6]); - -#define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock);\ - data->value = IN_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock);\ - return count; \ -} -set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); -set_in(min1, in_min[1], LM80_REG_IN_MIN(1)); -set_in(min2, in_min[2], LM80_REG_IN_MIN(2)); -set_in(min3, in_min[3], LM80_REG_IN_MIN(3)); -set_in(min4, in_min[4], LM80_REG_IN_MIN(4)); -set_in(min5, in_min[5], LM80_REG_IN_MIN(5)); -set_in(min6, in_min[6], LM80_REG_IN_MIN(6)); -set_in(max0, in_max[0], LM80_REG_IN_MAX(0)); -set_in(max1, in_max[1], LM80_REG_IN_MAX(1)); -set_in(max2, in_max[2], LM80_REG_IN_MAX(2)); -set_in(max3, in_max[3], LM80_REG_IN_MAX(3)); -set_in(max4, in_max[4], LM80_REG_IN_MAX(4)); -set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); -set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); - -#define show_fan(suffix, value, div) \ -static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ - DIV_FROM_REG(data->div))); \ -} -show_fan(min1, fan_min[0], fan_div[0]); -show_fan(min2, fan_min[1], fan_div[1]); -show_fan(input1, fan[0], fan_div[0]); -show_fan(input2, fan[1], fan_div[1]); - -#define show_fan_div(suffix, value) \ -static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ -} -show_fan_div(1, fan_div[0]); -show_fan_div(2, fan_div[1]); - -#define set_fan(suffix, value, reg, div) \ -static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock);\ - data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock);\ - return count; \ -} -set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); -set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - unsigned long min, val = simple_strtoul(buf, NULL, 10); - u8 reg; - - /* Save fan_min */ - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) - | (data->fan_div[nr] << (2 * (nr + 1))); - lm80_write_value(client, LM80_REG_FANDIV, reg); - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define set_fan_div(number) \ -static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, number - 1); \ -} -set_fan_div(1); -set_fan_div(2); - -static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm80_data *data = lm80_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); -} - -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ -} -show_temp(hot_max, temp_hot_max); -show_temp(hot_hyst, temp_hot_hyst); -show_temp(os_max, temp_os_max); -show_temp(os_hyst, temp_os_hyst); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_LIMIT_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); -set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); -set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); -set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm80_data *data = lm80_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); -static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1); -static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2); -static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3); -static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4); -static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5); -static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6); -static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0); -static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1); -static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2); -static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3); -static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4); -static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5); -static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6); -static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); -static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); -static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL); -static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL); -static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, - set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, - set_fan_min2); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, - set_temp_hot_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, - set_temp_hot_hyst); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, - set_temp_os_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, - set_temp_os_hyst); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm80_detect); -} - -int lm80_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct lm80_data *data; - int err = 0; - const char *name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm80_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) - goto error_free; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(new_client, i); - if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) - goto error_free; - } - - /* Determine the chip type - only one kind supported! */ - kind = lm80; - name = "lm80"; - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, 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 error_free; - - /* Initialize the LM80 chip */ - lm80_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error_free: - kfree(data); -exit: - return err; -} - -static int lm80_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 lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static struct lm80_data *lm80_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - dev_dbg(&client->dev, "Starting lm80 update\n"); - for (i = 0; i <= 6; i++) { - data->in[i] = - lm80_read_value(client, LM80_REG_IN(i)); - data->in_min[i] = - lm80_read_value(client, LM80_REG_IN_MIN(i)); - data->in_max[i] = - lm80_read_value(client, LM80_REG_IN_MAX(i)); - } - data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); - data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); - data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN_MIN(2)); - - data->temp = - (lm80_read_value(client, LM80_REG_TEMP) << 8) | - (lm80_read_value(client, LM80_REG_RES) & 0xf0); - data->temp_os_max = - lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = - lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = - lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = - lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client, LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + - (lm80_read_value(client, LM80_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm80_init(void) -{ - return i2c_add_driver(&lm80_driver); -} - -static void __exit sensors_lm80_exit(void) -{ - i2c_del_driver(&lm80_driver); -} - -MODULE_AUTHOR("Frodo Looijaard and " - "Philip Edelbrock "); -MODULE_DESCRIPTION("LM80 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm80_init); -module_exit(sensors_lm80_exit); diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c deleted file mode 100644 index a49008b444c..00000000000 --- a/drivers/i2c/chips/lm83.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * lm83.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is - * a sensor chip made by National Semiconductor. It reports up to four - * temperatures (its own plus up to three external ones) with a 1 deg - * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained - * from National's website at: - * http://www.national.com/pf/LM/LM83.html - * Since the datasheet omits to give the chip stepping code, I give it - * here: 0x03 (at register 0xff). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is selected using 2 three-level pins, resulting in 9 possible - * addresses. - */ - -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm83); - -/* - * The LM83 registers - * Manufacturer ID is 0x01 for National Semiconductor. - */ - -#define LM83_REG_R_MAN_ID 0xFE -#define LM83_REG_R_CHIP_ID 0xFF -#define LM83_REG_R_CONFIG 0x03 -#define LM83_REG_W_CONFIG 0x09 -#define LM83_REG_R_STATUS1 0x02 -#define LM83_REG_R_STATUS2 0x35 -#define LM83_REG_R_LOCAL_TEMP 0x00 -#define LM83_REG_R_LOCAL_HIGH 0x05 -#define LM83_REG_W_LOCAL_HIGH 0x0B -#define LM83_REG_R_REMOTE1_TEMP 0x30 -#define LM83_REG_R_REMOTE1_HIGH 0x38 -#define LM83_REG_W_REMOTE1_HIGH 0x50 -#define LM83_REG_R_REMOTE2_TEMP 0x01 -#define LM83_REG_R_REMOTE2_HIGH 0x07 -#define LM83_REG_W_REMOTE2_HIGH 0x0D -#define LM83_REG_R_REMOTE3_TEMP 0x31 -#define LM83_REG_R_REMOTE3_HIGH 0x3A -#define LM83_REG_W_REMOTE3_HIGH 0x52 -#define LM83_REG_R_TCRIT 0x42 -#define LM83_REG_W_TCRIT 0x5A - -/* - * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. - */ - -#define TEMP_FROM_REG(val) ((val) * 1000) -#define TEMP_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) - -static const u8 LM83_REG_R_TEMP[] = { - LM83_REG_R_LOCAL_TEMP, - LM83_REG_R_REMOTE1_TEMP, - LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP, - LM83_REG_R_LOCAL_HIGH, - LM83_REG_R_REMOTE1_HIGH, - LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH, - LM83_REG_R_TCRIT, -}; - -static const u8 LM83_REG_W_HIGH[] = { - LM83_REG_W_LOCAL_HIGH, - LM83_REG_W_REMOTE1_HIGH, - LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH, - LM83_REG_W_TCRIT, -}; - -/* - * Functions declaration - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter); -static int lm83_detect(struct i2c_adapter *adapter, int address, int kind); -static int lm83_detach_client(struct i2c_client *client); -static struct lm83_data *lm83_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm83_driver = { - .owner = THIS_MODULE, - .name = "lm83", - .id = I2C_DRIVERID_LM83, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm83_attach_adapter, - .detach_client = lm83_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm83_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp[9]; /* 0..3: input 1-4, - 4..7: high limit 1-4, - 8 : critical limit */ - u16 alarms; /* bitvector, combined */ -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm83_data *data = lm83_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); -} - -static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - data->temp[nr] = TEMP_TO_REG(val); - i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], - data->temp[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm83_data *data = lm83_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); -static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); -static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 4); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 5); -static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 6); -static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 7); -static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); -static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, - set_temp, 8); -static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm83_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm83_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm83_data)); - - /* The common I2C client data is placed right after the - * LM83-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm83_driver; - new_client->flags = 0; - - /* Now we do the detection and identification. A negative kind - * means that the driver was loaded with no force parameter - * (default), so we must both detect and identify the chip - * (actually there is only one possible kind of chip for now, LM83). - * A zero kind means that the driver was loaded with the force - * parameter, the detection step shall be skipped. A positive kind - * means that the driver was loaded with the force parameter and a - * given kind of chip is requested, so both the detection and the - * identification steps are skipped. */ - - /* Default to an LM83 if forced */ - if (kind == 0) - kind = lm83; - - if (kind < 0) { /* detection */ - if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) - & 0xA8) != 0x00) || - ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) - & 0x48) != 0x00) || - ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) - & 0x41) != 0x00)) { - dev_dbg(&adapter->dev, - "LM83 detection failed at 0x%02x.\n", address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - LM83_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM83_REG_R_CHIP_ID); - - if (man_id == 0x01) { /* National Semiconductor */ - if (chip_id == 0x03) { - kind = lm83; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == lm83) { - name = "lm83"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* - * Initialize the LM83 chip - * (Nothing to do for this one.) - */ - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm83_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 struct lm83_data *lm83_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int nr; - - dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 9; nr++) { - data->temp[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_TEMP[nr]); - } - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) - + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) - << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm83_init(void) -{ - return i2c_add_driver(&lm83_driver); -} - -static void __exit sensors_lm83_exit(void) -{ - i2c_del_driver(&lm83_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM83 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm83_init); -module_exit(sensors_lm83_exit); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c deleted file mode 100644 index b4d7fd41826..00000000000 --- a/drivers/i2c/chips/lm85.c +++ /dev/null @@ -1,1575 +0,0 @@ -/* - lm85.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - Copyright (c) 2004 Justin Thiessen - - Chip details at - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); - -/* The LM85 registers */ - -#define LM85_REG_IN(nr) (0x20 + (nr)) -#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) -#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) - -#define LM85_REG_TEMP(nr) (0x25 + (nr)) -#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) -#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) - -/* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) *2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) - -#define LM85_REG_PWM(nr) (0x30 + (nr)) - -#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) - -#define ADT7463_REG_TMIN_CTL1 0x36 -#define ADT7463_REG_TMIN_CTL2 0x37 - -#define LM85_REG_DEVICE 0x3d -#define LM85_REG_COMPANY 0x3e -#define LM85_REG_VERSTEP 0x3f -/* These are the recognized values for the above regs */ -#define LM85_DEVICE_ADX 0x27 -#define LM85_COMPANY_NATIONAL 0x01 -#define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_LM85C 0x60 -#define LM85_VERSTEP_LM85B 0x62 -#define LM85_VERSTEP_ADM1027 0x60 -#define LM85_VERSTEP_ADT7463 0x62 -#define LM85_VERSTEP_ADT7463C 0x6A -#define LM85_VERSTEP_EMC6D100_A0 0x60 -#define LM85_VERSTEP_EMC6D100_A1 0x61 -#define LM85_VERSTEP_EMC6D102 0x65 - -#define LM85_REG_CONFIG 0x40 - -#define LM85_REG_ALARM1 0x41 -#define LM85_REG_ALARM2 0x42 - -#define LM85_REG_VID 0x43 - -/* Automated FAN control */ -#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) -#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) -#define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_SPIKE2 0x63 -#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) -#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) -#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) -#define LM85_REG_AFAN_HYST1 0x6d -#define LM85_REG_AFAN_HYST2 0x6e - -#define LM85_REG_TACH_MODE 0x74 -#define LM85_REG_SPINUP_CTL 0x75 - -#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) -#define ADM1027_REG_CONFIG2 0x73 -#define ADM1027_REG_INTMASK1 0x74 -#define ADM1027_REG_INTMASK2 0x75 -#define ADM1027_REG_EXTEND_ADC1 0x76 -#define ADM1027_REG_EXTEND_ADC2 0x77 -#define ADM1027_REG_CONFIG3 0x78 -#define ADM1027_REG_FAN_PPR 0x7b - -#define ADT7463_REG_THERM 0x79 -#define ADT7463_REG_THERM_LIMIT 0x7A - -#define EMC6D100_REG_ALARM3 0x7d -/* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) -#define EMC6D102_REG_EXTEND_ADC1 0x85 -#define EMC6D102_REG_EXTEND_ADC2 0x86 -#define EMC6D102_REG_EXTEND_ADC3 0x87 -#define EMC6D102_REG_EXTEND_ADC4 0x88 - -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x8000 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors */ -static int lm85_scaling[] = { /* .001 Volts */ - 2500, 2250, 3300, 5000, 12000, - 3300, 1500, 1800 /*EMC6D100*/ - }; -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) - -#define INS_TO_REG(n,val) \ - SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) - -#define INSEXT_FROM_REG(n,val,ext,scale) \ - SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) - -#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) - -/* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) - -/* Temperature is reported in .001 degC increments */ -#define TEMP_TO_REG(val) \ - SENSORS_LIMIT(SCALE(val,1000,1),-127,127) -#define TEMPEXT_FROM_REG(val,ext,scale) \ - SCALE((val)*scale + (ext),scale,1000) -#define TEMP_FROM_REG(val) \ - TEMPEXT_FROM_REG(val,0,1) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - - -/* ZONEs have the following parameters: - * Limit (low) temp, 1. degC - * Hysteresis (below limit), 1. degC (0-15) - * Range of speed control, .1 degC (2-80) - * Critical (high) temp, 1. degC - * - * FAN PWMs have the following parameters: - * Reference Zone, 1, 2, 3, etc. - * Spinup time, .05 sec - * PWM value at limit/low temp, 1 count - * PWM Frequency, 1. Hz - * PWM is Min or OFF below limit, flag - * Invert PWM output, flag - * - * Some chips filter the temp, others the fan. - * Filter constant (or disabled) .1 seconds - */ - -/* These are the zone temperature range encodings in .001 degree C */ -static int lm85_range_map[] = { - 2000, 2500, 3300, 4000, 5000, 6600, - 8000, 10000, 13300, 16000, 20000, 26600, - 32000, 40000, 53300, 80000 - }; -static int RANGE_TO_REG( int range ) -{ - int i; - - if ( range < lm85_range_map[0] ) { - return 0 ; - } else if ( range > lm85_range_map[15] ) { - return 15 ; - } else { /* find closest match */ - for ( i = 14 ; i >= 0 ; --i ) { - if ( range > lm85_range_map[i] ) { /* range bracketed */ - if ((lm85_range_map[i+1] - range) < - (range - lm85_range_map[i])) { - i++; - break; - } - break; - } - } - } - return( i & 0x0f ); -} -#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) - -/* These are the Acoustic Enhancement, or Temperature smoothing encodings - * NOTE: The enable/disable bit is INCLUDED in these encodings as the - * MSB (bit 3, value 8). If the enable bit is 0, the encoded value - * is ignored, or set to 0. - */ -/* These are the PWM frequency encodings */ -static int lm85_freq_map[] = { /* .1 Hz */ - 100, 150, 230, 300, 380, 470, 620, 940 - }; -static int FREQ_TO_REG( int freq ) -{ - int i; - - if( freq >= lm85_freq_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( freq <= lm85_freq_map[i] ) - break ; - return( i & 0x07 ); -} -#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) - -/* Since we can't use strings, I'm abusing these numbers - * to stand in for the following meanings: - * 1 -- PWM responds to Zone 1 - * 2 -- PWM responds to Zone 2 - * 3 -- PWM responds to Zone 3 - * 23 -- PWM responds to the higher temp of Zone 2 or 3 - * 123 -- PWM responds to highest of Zone 1, 2, or 3 - * 0 -- PWM is always at 0% (ie, off) - * -1 -- PWM is always at 100% - * -2 -- PWM responds to manual control - */ - -static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) - -static int ZONE_TO_REG( int zone ) -{ - int i; - - for( i = 0 ; i <= 7 ; ++i ) - if( zone == lm85_zone_map[i] ) - break ; - if( i > 7 ) /* Not found. */ - i = 3; /* Always 100% */ - return( (i & 0x07)<<5 ); -} - -#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) -#define HYST_FROM_REG(val) ((val)*1000) - -#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OFFSET_FROM_REG(val) ((val)*25) - -#define PPR_MASK(fan) (0x03<<(fan *2)) -#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) -#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) - -/* i2c-vid.h defines vid_from_reg() */ -#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) - -/* Unlike some other drivers we DO NOT set initial limits. Use - * the config file to set limits. Some users have reported - * motherboards shutting down when we set limits in a previous - * version of the driver. - */ - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * given the automatic PWM fan control that is possible. There - * are about 47 bytes of config data to only 22 bytes of actual - * readings. So, we keep the config data up to date in the cache - * when it is written and only sample it once every 1 *minute* - */ -#define LM85_DATA_INTERVAL (HZ + HZ / 2) -#define LM85_CONFIG_INTERVAL (1 * 60 * HZ) - -/* For each registered LM85, we need to keep some data in memory. That - data is pointed to by lm85_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm85 client is - allocated. */ - -/* LM85 can automatically adjust fan speeds based on temperature - * This structure encapsulates an entire Zone config. There are - * three zones (one for each temperature input) on the lm85 - */ -struct lm85_zone { - s8 limit; /* Low temp limit */ - u8 hyst; /* Low limit hysteresis. (0-15) */ - u8 range; /* Temp range, encoded */ - s8 critical; /* "All fans ON" temp limit */ - u8 off_desired; /* Actual "off" temperature specified. Preserved - * to prevent "drift" as other autofan control - * values change. - */ - u8 max_desired; /* Actual "max" temperature specified. Preserved - * to prevent "drift" as other autofan control - * values change. - */ -}; - -struct lm85_autofan { - u8 config; /* Register value */ - u8 freq; /* PWM frequency, encoded */ - u8 min_pwm; /* Minimum PWM value, encoded */ - u8 min_off; /* Min PWM or OFF below "limit", flag */ -}; - -struct lm85_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[8]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u16 fan[4]; /* Register value */ - u16 fan_min[4]; /* Register value */ - u8 pwm[3]; /* Register value */ - u8 spinup_ctl; /* Register encoding, combined */ - u8 tach_mode; /* Register encoding, combined */ - u8 temp_ext[3]; /* Decoded values */ - u8 in_ext[8]; /* Decoded values */ - u8 adc_scale; /* ADC Extended bits scaling factor */ - u8 fan_ppr; /* Register value */ - u8 smooth[3]; /* Register encoding */ - u8 vid; /* Register value */ - u8 vrm; /* VRM version */ - u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ - u8 oppoint[3]; /* Register value */ - u16 tmin_ctl; /* Register value */ - unsigned long therm_total; /* Cummulative therm count */ - u8 therm_limit; /* Register value */ - u32 alarms; /* Register encoding, combined */ - struct lm85_autofan autofan[3]; - struct lm85_zone zone[3]; -}; - -static int lm85_attach_adapter(struct i2c_adapter *adapter); -static int lm85_detect(struct i2c_adapter *adapter, int address, - int kind); -static int lm85_detach_client(struct i2c_client *client); - -static int lm85_read_value(struct i2c_client *client, u8 register); -static int lm85_write_value(struct i2c_client *client, u8 register, int value); -static struct lm85_data *lm85_update_device(struct device *dev); -static void lm85_init_client(struct i2c_client *client); - - -static struct i2c_driver lm85_driver = { - .owner = THIS_MODULE, - .name = "lm85", - .id = I2C_DRIVERID_LM85, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm85_attach_adapter, - .detach_client = lm85_detach_client, -}; - - -/* 4 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); -} -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val); - lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); -show_fan_offset(4); - -/* vid, vrm, alarms */ - -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} - -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); - -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} - -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - return count; -} - -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); - -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); - -/* pwm */ - -static ssize_t show_pwm(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); -} -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm[nr] = PWM_TO_REG(val); - lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - int pwm_zone; - - pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); - return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) ); -} - -#define show_pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ - show_pwm_enable##offset, NULL); - -show_pwm_reg(1); -show_pwm_reg(2); -show_pwm_reg(3); - -/* Voltages */ - -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, - data->in[nr], - data->in_ext[nr], - data->adc_scale) ); -} -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); -} -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = INS_TO_REG(nr, val); - lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); -} -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = INS_TO_REG(nr, val); - lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} -#define show_in_reg(offset) \ -static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ - NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_##offset##_min, set_in_##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_##offset##_max, set_in_##offset##_max); - -show_in_reg(0); -show_in_reg(1); -show_in_reg(2); -show_in_reg(3); -show_in_reg(4); - -/* Temps */ - -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], - data->temp_ext[nr], - data->adc_scale) ); -} -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); -} -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); -} -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); - -show_temp_reg(1); -show_temp_reg(2); -show_temp_reg(3); - - -/* Automatic PWM control */ - -static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); -} -static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) - | ZONE_TO_REG(val) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), - data->autofan[nr].config); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); -} -static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].min_pwm = PWM_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), - data->autofan[nr].min_pwm); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", data->autofan[nr].min_off); -} -static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].min_off = val; - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); -} -static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].freq = FREQ_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - up(&data->update_lock); - return count; -} -#define pwm_auto(offset) \ -static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_channels(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_channels(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_channels, \ - set_pwm##offset##_auto_channels); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_min, \ - set_pwm##offset##_auto_pwm_min); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_minctl, \ - set_pwm##offset##_auto_pwm_minctl); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_freq, \ - set_pwm##offset##_auto_pwm_freq); -pwm_auto(1); -pwm_auto(2); -pwm_auto(3); - -/* Temperature settings for automatic PWM control */ - -static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - - HYST_FROM_REG(data->zone[nr].hyst)); -} -static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int min; - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - min = TEMP_FROM_REG(data->zone[nr].limit); - data->zone[nr].off_desired = TEMP_TO_REG(val); - data->zone[nr].hyst = HYST_TO_REG(min - val); - if ( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); -} -static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->zone[nr].limit = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), - data->zone[nr].limit); - -/* Update temp_auto_max and temp_auto_range */ - data->zone[nr].range = RANGE_TO_REG( - TEMP_FROM_REG(data->zone[nr].max_desired) - - TEMP_FROM_REG(data->zone[nr].limit)); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - ((data->zone[nr].range & 0x0f) << 4) - | (data->autofan[nr].freq & 0x07)); - -/* Update temp_auto_hyst and temp_auto_off */ - data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG( - data->zone[nr].limit) - TEMP_FROM_REG( - data->zone[nr].off_desired)); - if ( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + - RANGE_FROM_REG(data->zone[nr].range)); -} -static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int min; - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - min = TEMP_FROM_REG(data->zone[nr].limit); - data->zone[nr].max_desired = TEMP_TO_REG(val); - data->zone[nr].range = RANGE_TO_REG( - val - min); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - ((data->zone[nr].range & 0x0f) << 4) - | (data->autofan[nr].freq & 0x07)); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); -} -static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->zone[nr].critical = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), - data->zone[nr].critical); - up(&data->update_lock); - return count; -} -#define temp_auto(offset) \ -static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_off, \ - set_temp##offset##_auto_temp_off); \ -static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_min, \ - set_temp##offset##_auto_temp_min); \ -static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_max, \ - set_temp##offset##_auto_temp_max); \ -static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_crit, \ - set_temp##offset##_auto_temp_crit); -temp_auto(1); -temp_auto(2); -temp_auto(3); - -int lm85_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm85_detect); -} - -int lm85_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int company, verstep ; - struct i2c_client *new_client = NULL; - struct lm85_data *data; - int err = 0; - const char *type_name = ""; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - }; - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm85_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct lm85_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm85_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = lm85_read_value(new_client, LM85_REG_COMPANY); - verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); - - dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep); - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { - dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); - if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85C ) { - kind = lm85c ; - } else if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85B ) { - kind = lm85b ; - } else if( company == LM85_COMPANY_NATIONAL - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { - dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" - " Defaulting to LM85.\n", verstep); - kind = any_chip ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && verstep == LM85_VERSTEP_ADM1027 ) { - kind = adm1027 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep == LM85_VERSTEP_ADT7463 - || verstep == LM85_VERSTEP_ADT7463C) ) { - kind = adt7463 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { - dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_SMSC - && (verstep == LM85_VERSTEP_EMC6D100_A0 - || verstep == LM85_VERSTEP_EMC6D100_A1) ) { - /* Unfortunately, we can't tell a '100 from a '101 - * from the registers. Since a '101 is a '100 - * in a package with fewer pins and therefore no - * 3.3V, 1.5V or 1.8V inputs, perhaps if those - * inputs read 0, then it's a '101. - */ - kind = emc6d100 ; - } else if( company == LM85_COMPANY_SMSC - && verstep == LM85_VERSTEP_EMC6D102) { - kind = emc6d102 ; - } else if( company == LM85_COMPANY_SMSC - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - dev_err(&adapter->dev, "lm85: Detected SMSC chip\n"); - dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( kind == any_chip - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); - /* Leave kind as "any_chip" */ - } else { - dev_dbg(&adapter->dev, "Autodetection failed\n"); - /* Not an LM85 ... */ - if( kind == any_chip ) { /* User used force=x,y */ - dev_err(&adapter->dev, "Generic LM85 Version 6 not" - " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); - } - err = 0 ; - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - if ( kind == any_chip ) { - type_name = "lm85"; - } else if ( kind == lm85b ) { - type_name = "lm85b"; - } else if ( kind == lm85c ) { - type_name = "lm85c"; - } else if ( kind == adm1027 ) { - type_name = "adm1027"; - } else if ( kind == adt7463 ) { - type_name = "adt7463"; - } else if ( kind == emc6d100){ - type_name = "emc6d100"; - } else if ( kind == emc6d102 ) { - type_name = "emc6d102"; - } - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); - - /* Fill in the remaining client fields */ - data->type = kind; - 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 ERROR1; - - /* Set the VRM version */ - data->vrm = i2c_which_vrm(); - - /* Initialize the LM85 chip */ - lm85_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan4_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan4_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit); - - return 0; - - /* Error out and cleanup code */ - ERROR1: - kfree(data); - ERROR0: - return err; -} - -int lm85_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - - -int lm85_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - /* What size location is it? */ - switch( reg ) { - case LM85_REG_FAN(0) : /* Read WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case LM85_REG_ALARM1 : /* Read both bytes at once */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */ - res = i2c_smbus_read_byte_data(client, reg) << 8 ; - res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; - break ; - default: /* Read BYTE data */ - res = i2c_smbus_read_byte_data(client, reg); - break ; - } - - return res ; -} - -int lm85_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res ; - - switch( reg ) { - case LM85_REG_FAN(0) : /* Write WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - /* NOTE: ALARM is read only, so not included here */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; - res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */ - res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; - break ; - default: /* Write BYTE data */ - res = i2c_smbus_write_byte_data(client, reg, value); - break ; - } - - return res ; -} - -void lm85_init_client(struct i2c_client *client) -{ - int value; - struct lm85_data *data = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "Initializing device\n"); - - /* Warn if part was not "READY" */ - value = lm85_read_value(client, LM85_REG_CONFIG); - dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); - if( value & 0x02 ) { - dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( ! (value & 0x04) ) { - dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( value & 0x10 - && ( data->type == adm1027 - || data->type == adt7463 ) ) { - dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " - "Please report this to the lm85 maintainer.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. - */ - - /* Start monitoring */ - value = lm85_read_value(client, LM85_REG_CONFIG); - /* Try to clear LOCK, Set START, save everything else */ - value = (value & ~ 0x02) | 0x01 ; - dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); - lm85_write_value(client, LM85_REG_CONFIG, value); -} - -static struct lm85_data *lm85_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if ( !data->valid || - time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { - /* Things that change quickly */ - dev_dbg(&client->dev, "Reading sensor values\n"); - - /* Have to read extended bits first to "freeze" the - * more significant bits that are read later. - */ - if ( (data->type == adm1027) || (data->type == adt7463) ) { - int ext1 = lm85_read_value(client, - ADM1027_REG_EXTEND_ADC1); - int ext2 = lm85_read_value(client, - ADM1027_REG_EXTEND_ADC2); - int val = (ext1 << 8) + ext2; - - for(i = 0; i <= 4; i++) - data->in_ext[i] = (val>>(i * 2))&0x03; - - for(i = 0; i <= 2; i++) - data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; - } - - /* adc_scale is 2^(number of LSBs). There are 4 extra bits in - the emc6d102 and 2 in the adt7463 and adm1027. In all - other chips ext is always 0 and the value of scale is - irrelevant. So it is left in 4*/ - data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; - - for (i = 0; i <= 4; ++i) { - data->in[i] = - lm85_read_value(client, LM85_REG_IN(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan[i] = - lm85_read_value(client, LM85_REG_FAN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp[i] = - lm85_read_value(client, LM85_REG_TEMP(i)); - } - - for (i = 0; i <= 2; ++i) { - data->pwm[i] = - lm85_read_value(client, LM85_REG_PWM(i)); - } - - data->alarms = lm85_read_value(client, LM85_REG_ALARM1); - - if ( data->type == adt7463 ) { - if( data->therm_total < ULONG_MAX - 256 ) { - data->therm_total += - lm85_read_value(client, ADT7463_REG_THERM ); - } - } else if ( data->type == emc6d100 ) { - /* Three more voltage sensors */ - for (i = 5; i <= 7; ++i) { - data->in[i] = - lm85_read_value(client, EMC6D100_REG_IN(i)); - } - /* More alarm bits */ - data->alarms |= - lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - } else if (data->type == emc6d102 ) { - /* Have to read LSB bits after the MSB ones because - the reading of the MSB bits has frozen the - LSBs (backward from the ADM1027). - */ - int ext1 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC1); - int ext2 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC2); - int ext3 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC3); - int ext4 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC4); - data->in_ext[0] = ext3 & 0x0f; - data->in_ext[1] = ext4 & 0x0f; - data->in_ext[2] = (ext4 >> 4) & 0x0f; - data->in_ext[3] = (ext3 >> 4) & 0x0f; - data->in_ext[4] = (ext2 >> 4) & 0x0f; - - data->temp_ext[0] = ext1 & 0x0f; - data->temp_ext[1] = ext2 & 0x0f; - data->temp_ext[2] = (ext1 >> 4) & 0x0f; - } - - data->last_reading = jiffies ; - }; /* last_reading */ - - if ( !data->valid || - time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - dev_dbg(&client->dev, "Reading config values\n"); - - for (i = 0; i <= 4; ++i) { - data->in_min[i] = - lm85_read_value(client, LM85_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, LM85_REG_IN_MAX(i)); - } - - if ( data->type == emc6d100 ) { - for (i = 5; i <= 7; ++i) { - data->in_min[i] = - lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); - } - } - - for (i = 0; i <= 3; ++i) { - data->fan_min[i] = - lm85_read_value(client, LM85_REG_FAN_MIN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp_min[i] = - lm85_read_value(client, LM85_REG_TEMP_MIN(i)); - data->temp_max[i] = - lm85_read_value(client, LM85_REG_TEMP_MAX(i)); - } - - data->vid = lm85_read_value(client, LM85_REG_VID); - - for (i = 0; i <= 2; ++i) { - int val ; - data->autofan[i].config = - lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); - val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); - data->autofan[i].freq = val & 0x07 ; - data->zone[i].range = (val >> 4) & 0x0f ; - data->autofan[i].min_pwm = - lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); - data->zone[i].limit = - lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); - data->zone[i].critical = - lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); - } - - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f ; - data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ - data->autofan[0].min_off = (i & 0x20) != 0 ; - data->autofan[1].min_off = (i & 0x40) != 0 ; - data->autofan[2].min_off = (i & 0x80) != 0 ; - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i>>4) & 0x0f ; - data->smooth[2] = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i>>4) & 0x0f ; - data->zone[1].hyst = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i>>4) & 0x0f ; - - if ( (data->type == lm85b) || (data->type == lm85c) ) { - data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE ); - data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL ); - } else if ( (data->type == adt7463) || (data->type == adm1027) ) { - if ( data->type == adt7463 ) { - for (i = 0; i <= 2; ++i) { - data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i) ); - } - data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL1 ); - data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT ); - } - for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i) ); - } - data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3 ); - data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR ); - } - - data->last_config = jiffies; - }; /* last_config */ - - data->valid = 1; - - up(&data->update_lock); - - return data; -} - - -static int __init sm_lm85_init(void) -{ - return i2c_add_driver(&lm85_driver); -} - -static void __exit sm_lm85_exit(void) -{ - i2c_del_driver(&lm85_driver); -} - -/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. - * Thanks to Margit Schubert-While for help with - * post 2.7.0 CVS changes. - */ -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny , Margit Schubert-While , Justin Thiessen - * Philip Edelbrock - * Stephen Rousset - * Dan Eaton - * Copyright (C) 2004 Jean Delvare - * - * Original port to Linux 2.6 by Jeff Oliver. - * - * The LM87 is a sensor chip made by National Semiconductor. It monitors up - * to 8 voltages (including its own power source), up to three temperatures - * (its own plus up to two external ones) and up to two fans. The default - * configuration is 6 voltages, two temperatures and two fans (see below). - * Voltages are scaled internally with ratios such that the nominal value of - * each voltage correspond to a register value of 192 (which means a - * resolution of about 0.5% of the nominal value). Temperature values are - * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete - * datasheet can be obtained from National's website at: - * http://www.national.com/pf/LM/LM87.html - * - * Some functions share pins, so not all functions are available at the same - * time. Which are depends on the hardware setup. This driver assumes that - * the BIOS configured the chip correctly. In that respect, it differs from - * the original driver (from lm_sensors for Linux 2.4), which would force the - * LM87 to an arbitrary, compile-time chosen mode, regardless of the actual - * chipset wiring. - * For reference, here is the list of exclusive functions: - * - in0+in5 (default) or temp3 - * - fan1 (default) or in6 - * - fan2 (default) or in7 - * - VID lines (default) or IRQ lines (not handled by this driver) - * - * The LM87 additionally features an analog output, supposedly usable to - * control the speed of a fan. All new chips use pulse width modulation - * instead. The LM87 is the only hardware monitoring chipset I know of - * which uses amplitude modulation. Be careful when using this feature. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e. - */ - -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm87); - -/* - * The LM87 registers - */ - -/* nr in 0..5 */ -#define LM87_REG_IN(nr) (0x20 + (nr)) -#define LM87_REG_IN_MAX(nr) (0x2B + (nr) * 2) -#define LM87_REG_IN_MIN(nr) (0x2C + (nr) * 2) -/* nr in 0..1 */ -#define LM87_REG_AIN(nr) (0x28 + (nr)) -#define LM87_REG_AIN_MIN(nr) (0x1A + (nr)) -#define LM87_REG_AIN_MAX(nr) (0x3B + (nr)) - -static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 }; -static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B }; -static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; - -#define LM87_REG_TEMP_HW_INT_LOCK 0x13 -#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 -#define LM87_REG_TEMP_HW_INT 0x17 -#define LM87_REG_TEMP_HW_EXT 0x18 - -/* nr in 0..1 */ -#define LM87_REG_FAN(nr) (0x28 + (nr)) -#define LM87_REG_FAN_MIN(nr) (0x3B + (nr)) -#define LM87_REG_AOUT 0x19 - -#define LM87_REG_CONFIG 0x40 -#define LM87_REG_CHANNEL_MODE 0x16 -#define LM87_REG_VID_FAN_DIV 0x47 -#define LM87_REG_VID4 0x49 - -#define LM87_REG_ALARMS1 0x41 -#define LM87_REG_ALARMS2 0x42 - -#define LM87_REG_COMPANY_ID 0x3E -#define LM87_REG_REVISION 0x3F - -/* - * Conversions and various macros - * The LM87 uses signed 8-bit values for temperatures. - */ - -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ - (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) -#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ - (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) - -#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ - 1350000 + (reg)*(div) / 2) / ((reg)*(div)) -#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ - (1350000 + (val)*(div) / 2) / ((val)*(div))) - -#define FAN_DIV_FROM_REG(reg) (1 << (reg)) - -/* analog out is 9.80mV/LSB */ -#define AOUT_FROM_REG(reg) (((reg) * 98 + 5) / 10) -#define AOUT_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 2500 ? 255 : \ - ((val) * 10 + 49) / 98) - -/* nr in 0..1 */ -#define CHAN_NO_FAN(nr) (1 << (nr)) -#define CHAN_TEMP3 (1 << 2) -#define CHAN_VCC_5V (1 << 3) -#define CHAN_NO_VID (1 << 8) - -/* - * Functions declaration - */ - -static int lm87_attach_adapter(struct i2c_adapter *adapter); -static int lm87_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm87_init_client(struct i2c_client *client); -static int lm87_detach_client(struct i2c_client *client); -static struct lm87_data *lm87_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm87_driver = { - .owner = THIS_MODULE, - .name = "lm87", - .id = I2C_DRIVERID_LM87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm87_attach_adapter, - .detach_client = lm87_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm87_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 channel; /* register value */ - - u8 in[8]; /* register value */ - u8 in_max[8]; /* register value */ - u8 in_min[8]; /* register value */ - u16 in_scale[8]; - - s8 temp[3]; /* register value */ - s8 temp_high[3]; /* register value */ - s8 temp_low[3]; /* register value */ - s8 temp_crit_int; /* min of two register values */ - s8 temp_crit_ext; /* min of two register values */ - - u8 fan[2]; /* register value */ - u8 fan_min[2]; /* register value */ - u8 fan_div[2]; /* register value, shifted right */ - u8 aout; /* register value */ - - u16 alarms; /* register values, combined */ - u8 vid; /* register values, combined */ - u8 vrm; -}; - -/* - * Sysfs stuff - */ - -static inline int lm87_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -#define show_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - data->in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset##_input, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); -show_in(6); -show_in(7); - -static void set_in_min(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) : - LM87_REG_AIN_MIN(nr-6), data->in_min[nr]); - up(&data->update_lock); -} - -static void set_in_max(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) : - LM87_REG_AIN_MAX(nr-6), data->in_max[nr]); - up(&data->update_lock); -} - -#define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_min(dev, buf, offset); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_max(dev, buf, offset); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); -set_in(0); -set_in(1); -set_in(2); -set_in(3); -set_in(4); -set_in(5); -set_in(6); -set_in(7); - -#define show_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ -} \ -static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); -show_temp(1); -show_temp(2); -show_temp(3); - -static void set_temp_low(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]); - up(&data->update_lock); -} - -static void set_temp_high(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]); - up(&data->update_lock); -} - -#define set_temp(offset) \ -static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_low(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_high(dev, buf, offset-1); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_high, set_temp##offset##_high); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_low, set_temp##offset##_low); -set_temp(1); -set_temp(2); -set_temp(3); - -static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); -} - -static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); -} - -static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); -static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); - -#define show_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset##_input, NULL); -show_fan(1); -show_fan(2); - -static void set_fan_min(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, - FAN_DIV_FROM_REG(data->fan_div[nr])); - lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - unsigned long min; - u8 reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - up(&data->update_lock); - return -EINVAL; - } - - reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - switch (nr) { - case 0: - reg = (reg & 0xCF) | (data->fan_div[0] << 4); - break; - case 1: - reg = (reg & 0x3F) | (data->fan_div[1] << 6); - break; - } - lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); - - data->fan_min[nr] = FAN_TO_REG(min, val); - lm87_write_value(client, LM87_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define set_fan(offset) \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - set_fan_min(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); -set_fan(1); -set_fan(2); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); -} -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->aout = AOUT_TO_REG(val); - lm87_write_value(client, LM87_REG_AOUT, data->aout); - up(&data->update_lock); - return count; -} -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); - -/* - * Real code - */ - -static int lm87_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm87_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm87_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm87_data)); - - /* The common I2C client data is placed right before the - LM87-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm87_driver; - new_client->flags = 0; - - /* Default to an LM87 if forced */ - if (kind == 0) - kind = lm87; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); - - if (rev < 0x01 || rev > 0x08 - || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { - dev_dbg(&adapter->dev, - "LM87 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM87 chip */ - lm87_init_client(new_client); - - data->in_scale[0] = 2500; - data->in_scale[1] = 2700; - data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300; - data->in_scale[3] = 5000; - data->in_scale[4] = 12000; - data->in_scale[5] = 2700; - data->in_scale[6] = 1875; - data->in_scale[7] = 1875; - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - - if (data->channel & CHAN_NO_FAN(0)) { - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); - } else { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - } - if (data->channel & CHAN_NO_FAN(1)) { - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in7_max); - } else { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - } - - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - - if (data->channel & CHAN_TEMP3) { - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - } else { - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - } - - if (!(data->channel & CHAN_NO_VID)) { - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - } - - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void lm87_init_client(struct i2c_client *client) -{ - struct lm87_data *data = i2c_get_clientdata(client); - u8 config; - - data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); - data->vrm = i2c_which_vrm(); - - config = lm87_read_value(client, LM87_REG_CONFIG); - if (!(config & 0x01)) { - int i; - - /* Limits are left uninitialized after power-up */ - for (i = 1; i < 6; i++) { - lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); - } - for (i = 0; i < 2; i++) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); - lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); - } - if (data->channel & CHAN_TEMP3) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); - } else { - lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); - } - } - if ((config & 0x81) != 0x01) { - /* Start monitoring */ - lm87_write_value(client, LM87_REG_CONFIG, - (config & 0xF7) | 0x01); - } -} - -static int lm87_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 struct lm87_data *lm87_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - dev_dbg(&client->dev, "Updating data.\n"); - - i = (data->channel & CHAN_TEMP3) ? 1 : 0; - j = (data->channel & CHAN_TEMP3) ? 5 : 6; - for (; i < j; i++) { - data->in[i] = lm87_read_value(client, - LM87_REG_IN(i)); - data->in_min[i] = lm87_read_value(client, - LM87_REG_IN_MIN(i)); - data->in_max[i] = lm87_read_value(client, - LM87_REG_IN_MAX(i)); - } - - for (i = 0; i < 2; i++) { - if (data->channel & CHAN_NO_FAN(i)) { - data->in[6+i] = lm87_read_value(client, - LM87_REG_AIN(i)); - data->in_max[6+i] = lm87_read_value(client, - LM87_REG_AIN_MAX(i)); - data->in_min[6+i] = lm87_read_value(client, - LM87_REG_AIN_MIN(i)); - - } else { - data->fan[i] = lm87_read_value(client, - LM87_REG_FAN(i)); - data->fan_min[i] = lm87_read_value(client, - LM87_REG_FAN_MIN(i)); - } - } - - j = (data->channel & CHAN_TEMP3) ? 3 : 2; - for (i = 0 ; i < j; i++) { - data->temp[i] = lm87_read_value(client, - LM87_REG_TEMP[i]); - data->temp_high[i] = lm87_read_value(client, - LM87_REG_TEMP_HIGH[i]); - data->temp_low[i] = lm87_read_value(client, - LM87_REG_TEMP_LOW[i]); - } - - i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); - data->temp_crit_int = min(i, j); - - i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); - data->temp_crit_ext = min(i, j); - - i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = (i & 0x0F) - | (lm87_read_value(client, LM87_REG_VID4) & 0x01) - << 4; - - data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) - | (lm87_read_value(client, LM87_REG_ALARMS2) - << 8); - data->aout = lm87_read_value(client, LM87_REG_AOUT); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm87_init(void) -{ - return i2c_add_driver(&lm87_driver); -} - -static void __exit sensors_lm87_exit(void) -{ - i2c_del_driver(&lm87_driver); -} - -MODULE_AUTHOR("Jean Delvare and others"); -MODULE_DESCRIPTION("LM87 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm87_init); -module_exit(sensors_lm87_exit); diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c deleted file mode 100644 index a67dcadf7cb..00000000000 --- a/drivers/i2c/chips/lm90.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * lm90.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Based on the lm83 driver. The LM90 is a sensor chip made by National - * Semiconductor. It reports up to two temperatures (its own plus up to - * one external one) with a 0.125 deg resolution (1 deg for local - * temperature) and a 3-4 deg accuracy. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM90.html - * - * This driver also supports the LM89 and LM99, two other sensor chips - * made by National Semiconductor. Both have an increased remote - * temperature measurement accuracy (1 degree), and the LM99 - * additionally shifts remote temperatures (measured and limits) by 16 - * degrees, which allows for higher temperatures measurement. The - * driver doesn't handle it since it can be done easily in user-space. - * Complete datasheets can be obtained from National's website at: - * http://www.national.com/pf/LM/LM89.html - * http://www.national.com/pf/LM/LM99.html - * Note that there is no way to differentiate between both chips. - * - * This driver also supports the LM86, another sensor chip made by - * National Semiconductor. It is exactly similar to the LM90 except it - * has a higher accuracy. - * Complete datasheet can be obtained from National's website at: - * http://www.national.com/pf/LM/LM86.html - * - * This driver also supports the ADM1032, a sensor chip made by Analog - * Devices. That chip is similar to the LM90, with a few differences - * that are not handled by this driver. Complete datasheet can be - * obtained from Analog's website at: - * http://products.analog.com/products/info.asp?product=ADM1032 - * Among others, it has a higher accuracy than the LM90, much like the - * LM86 does. - * - * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor - * chips made by Maxim. These chips are similar to the LM86. Complete - * datasheet can be obtained at Maxim's website at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Note that there is no easy way to differentiate between the three - * variants. The extra address and features of the MAX6659 are not - * supported by this driver. - * - * This driver also supports the ADT7461 chip from Analog Devices but - * only in its "compatability mode". If an ADT7461 chip is found but - * is configured in non-compatible mode (where its temperature - * register values are decoded differently) it is ignored by this - * driver. Complete datasheet can be obtained from Analog's website - * at: - * http://products.analog.com/products/info.asp?product=ADT7461 - * - * Since the LM90 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed except for - * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. - * LM89-1, and LM99-1 have address 0x4d. - * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - * ADT7461 always has address 0x4c. - */ - -static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); - -/* - * The LM90 registers - */ - -#define LM90_REG_R_MAN_ID 0xFE -#define LM90_REG_R_CHIP_ID 0xFF -#define LM90_REG_R_CONFIG1 0x03 -#define LM90_REG_W_CONFIG1 0x09 -#define LM90_REG_R_CONFIG2 0xBF -#define LM90_REG_W_CONFIG2 0xBF -#define LM90_REG_R_CONVRATE 0x04 -#define LM90_REG_W_CONVRATE 0x0A -#define LM90_REG_R_STATUS 0x02 -#define LM90_REG_R_LOCAL_TEMP 0x00 -#define LM90_REG_R_LOCAL_HIGH 0x05 -#define LM90_REG_W_LOCAL_HIGH 0x0B -#define LM90_REG_R_LOCAL_LOW 0x06 -#define LM90_REG_W_LOCAL_LOW 0x0C -#define LM90_REG_R_LOCAL_CRIT 0x20 -#define LM90_REG_W_LOCAL_CRIT 0x20 -#define LM90_REG_R_REMOTE_TEMPH 0x01 -#define LM90_REG_R_REMOTE_TEMPL 0x10 -#define LM90_REG_R_REMOTE_OFFSH 0x11 -#define LM90_REG_W_REMOTE_OFFSH 0x11 -#define LM90_REG_R_REMOTE_OFFSL 0x12 -#define LM90_REG_W_REMOTE_OFFSL 0x12 -#define LM90_REG_R_REMOTE_HIGHH 0x07 -#define LM90_REG_W_REMOTE_HIGHH 0x0D -#define LM90_REG_R_REMOTE_HIGHL 0x13 -#define LM90_REG_W_REMOTE_HIGHL 0x13 -#define LM90_REG_R_REMOTE_LOWH 0x08 -#define LM90_REG_W_REMOTE_LOWH 0x0E -#define LM90_REG_R_REMOTE_LOWL 0x14 -#define LM90_REG_W_REMOTE_LOWL 0x14 -#define LM90_REG_R_REMOTE_CRIT 0x19 -#define LM90_REG_W_REMOTE_CRIT 0x19 -#define LM90_REG_R_TCRIT_HYST 0x21 -#define LM90_REG_W_TCRIT_HYST 0x21 - -/* - * Conversions and various macros - * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define TEMP1_FROM_REG(val) ((val) * 1000) -#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) -#define TEMP2_FROM_REG(val) ((val) / 32 * 125) -#define TEMP2_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \ - ((val) + 500) / 1000) - -/* - * ADT7461 is almost identical to LM90 except that attempts to write - * values that are outside the range 0 < temp < 127 are treated as - * the boundary value. - */ - -#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127000 ? 127 : \ - ((val) + 500) / 1000) -#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127750 ? 0x7FC0 : \ - ((val) + 125) / 250 * 64) - -/* - * Functions declaration - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter); -static int lm90_detect(struct i2c_adapter *adapter, int address, - int kind); -static void lm90_init_client(struct i2c_client *client); -static int lm90_detach_client(struct i2c_client *client); -static struct lm90_data *lm90_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm90_driver = { - .owner = THIS_MODULE, - .name = "lm90", - .id = I2C_DRIVERID_LM90, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm90_attach_adapter, - .detach_client = lm90_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm90_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - int kind; - - /* registers values */ - s8 temp8[5]; /* 0: local input - 1: local low limit - 2: local high limit - 3: local critical limit - 4: remote critical limit */ - s16 temp11[3]; /* 0: remote input - 1: remote low limit - 2: remote high limit */ - u8 temp_hyst; - u8 alarms; /* bitvector */ -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); -} - -static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM90_REG_W_LOCAL_LOW, - LM90_REG_W_LOCAL_HIGH, - LM90_REG_W_LOCAL_CRIT, - LM90_REG_W_REMOTE_CRIT, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - if (data->kind == adt7461) - data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); - else - data->temp8[nr] = TEMP1_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); -} - -static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM90_REG_W_REMOTE_LOWH, - LM90_REG_W_REMOTE_LOWL, - LM90_REG_W_REMOTE_HIGHH, - LM90_REG_W_REMOTE_HIGHL, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - if (data->kind == adt7461) - data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); - else - data->temp11[nr] = TEMP2_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], - data->temp11[nr] >> 8); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], - data->temp11[nr] & 0xff); - up(&data->update_lock); - return count; -} - -static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) - - TEMP1_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - long hyst; - - down(&data->update_lock); - hyst = TEMP1_FROM_REG(data->temp8[3]) - val; - i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, - HYST_TO_REG(hyst)); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); -static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 1); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 2); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 2); -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 3); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 4); -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, - set_temphyst, 3); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm90_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm90_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm90_data)); - - /* The common I2C client data is placed right before the - LM90-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm90_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM90 if forced */ - if (kind == 0) - kind = lm90; - - if (kind < 0) { /* detection and identification */ - u8 man_id, chip_id, reg_config1, reg_convrate; - - man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1); - reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE); - - if (man_id == 0x01) { /* National Semiconductor */ - u8 reg_config2; - - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2); - - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { - if (address == 0x4C - && (chip_id & 0xF0) == 0x20) { /* LM90 */ - kind = lm90; - } else - if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ - kind = lm99; - } else - if (address == 0x4C - && (chip_id & 0xF0) == 0x10) { /* LM86 */ - kind = lm86; - } - } - } else - if (man_id == 0x41) { /* Analog Devices */ - if (address == 0x4C - && (chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) { - kind = adm1032; - } else - if (address == 0x4c - && chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ - && reg_convrate <= 0x0A) { - kind = adt7461; - } - } else - if (man_id == 0x4D) { /* Maxim */ - /* - * The Maxim variants do NOT have a chip_id register. - * Reading from that address will return the last read - * value, which in our case is those of the man_id - * register. Likewise, the config1 register seems to - * lack a low nibble, so the value will be those of the - * previous read, so in our case those of the man_id - * register. - */ - if (chip_id == man_id - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) { - kind = max6657; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == lm90) { - name = "lm90"; - } else if (kind == adm1032) { - name = "adm1032"; - } else if (kind == lm99) { - name = "lm99"; - } else if (kind == lm86) { - name = "lm86"; - } else if (kind == max6657) { - name = "max6657"; - } else if (kind == adt7461) { - name = "adt7461"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - data->kind = kind; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM90 chip */ - lm90_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_hyst.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void lm90_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, - 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); - if (config & 0x40) - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config & 0xBF); /* run */ -} - -static int lm90_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 struct lm90_data *lm90_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - u8 oldh, newh; - - dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp8[3] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp8[4] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); - data->temp_hyst = i2c_smbus_read_byte_data(client, - LM90_REG_R_TCRIT_HYST); - - /* - * There is a trick here. We have to read two registers to - * have the remote sensor temperature, but we have to beware - * a conversion could occur inbetween the readings. The - * datasheet says we should either use the one-shot - * conversion register, which we don't want to do (disables - * hardware monitoring) or monitor the busy bit, which is - * impossible (we can't read the values and monitor that bit - * at the exact same time). So the solution used here is to - * read the high byte once, then the low byte, then the high - * byte again. If the new high byte matches the old one, - * then we have a valid reading. Else we have to read the low - * byte again, and now we believe we have a correct reading. - */ - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); - newh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - if (newh != oldh) { - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); -#ifdef DEBUG - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp11[0] |= (newh << 8); - - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHL); - data->alarms = i2c_smbus_read_byte_data(client, - LM90_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm90_init(void) -{ - return i2c_add_driver(&lm90_driver); -} - -static void __exit sensors_lm90_exit(void) -{ - i2c_del_driver(&lm90_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM90/ADM1032 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm90_init); -module_exit(sensors_lm90_exit); diff --git a/drivers/i2c/chips/lm92.c b/drivers/i2c/chips/lm92.c deleted file mode 100644 index 215c8e40ffd..00000000000 --- a/drivers/i2c/chips/lm92.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * lm92 - Hardware monitoring driver - * Copyright (C) 2005 Jean Delvare - * - * Based on the lm90 driver, with some ideas taken from the lm_sensors - * lm92 driver as well. - * - * The LM92 is a sensor chip made by National Semiconductor. It reports - * its own temperature with a 0.0625 deg resolution and a 0.33 deg - * accuracy. Complete datasheet can be obtained from National's website - * at: - * http://www.national.com/pf/LM/LM92.html - * - * This driver also supports the MAX6635 sensor chip made by Maxim. - * This chip is compatible with the LM92, but has a lesser accuracy - * (1.0 deg). Complete datasheet can be obtained from Maxim's website - * at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 - * - * Since the LM92 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * Support could easily be added for the National Semiconductor LM76 - * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible - * with the LM92. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - - -/* The LM92 and MAX6635 have 2 two-state pins for address selection, - resulting in 4 possible addresses. */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm92); - -/* The LM92 registers */ -#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ -#define LM92_REG_TEMP 0x00 /* 16-bit, RO */ -#define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ -#define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ -#define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ -#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ -#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ - -/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, - left-justified in 16-bit registers. No rounding is done, with such - a resolution it's just not worth it. Note that the MAX6635 doesn't - make use of the 4 lower bits for limits (i.e. effective resolution - for limits is 1 degree Celsius). */ -static inline int TEMP_FROM_REG(s16 reg) -{ - return reg / 8 * 625 / 10; -} - -static inline s16 TEMP_TO_REG(int val) -{ - if (val <= -60000) - return -60000 * 10 / 625 * 8; - if (val >= 160000) - return 160000 * 10 / 625 * 8; - return val * 10 / 625 * 8; -} - -/* Alarm flags are stored in the 3 LSB of the temperature register */ -static inline u8 ALARMS_FROM_REG(s16 reg) -{ - return reg & 0x0007; -} - -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; - -/* Client data (each client gets its own) */ -struct lm92_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; -}; - - -/* - * Sysfs attributes and callback functions - */ - -static struct lm92_data *lm92_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { - dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP)); - data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST)); - data->temp1_crit = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT)); - data->temp1_min = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_LOW)); - data->temp1_max = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH)); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm92_data *data = lm92_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm92_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ - up(&data->update_lock); \ - return count; \ -} -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); - -static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - - TEMP_FROM_REG(data->temp1_hyst)); -} -static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - - TEMP_FROM_REG(data->temp1_hyst)); -} -static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) - + TEMP_FROM_REG(data->temp1_hyst)); -} - -static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; - i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, - swab16(TEMP_TO_REG(data->temp1_hyst))); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, - set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, - set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, - set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, - set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -/* - * Detection and registration - */ - -static void lm92_init_client(struct i2c_client *client) -{ - u8 config; - - /* Start the conversions if needed */ - config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); - if (config & 0x01) - i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, - config & 0xFE); -} - -/* The MAX6635 has no identification register, so we have to use tricks - to identify it reliably. This is somewhat slow. - Note that we do NOT rely on the 2 MSB of the configuration register - always reading 0, as suggested by the datasheet, because it was once - reported not to be true. */ -static int max6635_check(struct i2c_client *client) -{ - u16 temp_low, temp_high, temp_hyst, temp_crit; - u8 conf; - int i; - - /* No manufacturer ID register, so a read from this address will - always return the last read value. */ - temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW); - if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low) - return 0; - temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH); - if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high) - return 0; - - /* Limits are stored as integer values (signed, 9-bit). */ - if ((temp_low & 0x7f00) || (temp_high & 0x7f00)) - return 0; - temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST); - temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT); - if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) - return 0; - - /* Registers addresses were found to cycle over 16-byte boundaries. - We don't test all registers with all offsets so as to save some - reads and time, but this should still be sufficient to dismiss - non-MAX6635 chips. */ - conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); - for (i=16; i<96; i*=2) { - if (temp_hyst != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST + i - 16) - || temp_crit != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT + i) - || temp_low != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_LOW + i + 16) - || temp_high != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH + i + 32) - || conf != i2c_smbus_read_byte_data(client, - LM92_REG_CONFIG + i)) - return 0; - } - - return 1; -} - -/* The following function does more than just detection. If detection - succeeds, it also registers the new chip. */ -static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm92_data *data; - int err = 0; - char *name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm92_data)); - - /* Fill in enough client fields so that we can read from the chip, - which is required for identication */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm92_driver; - new_client->flags = 0; - - /* A negative kind means that the driver was loaded with no force - parameter (default), so we must identify the chip. */ - if (kind < 0) { - u8 config = i2c_smbus_read_byte_data(new_client, - LM92_REG_CONFIG); - u16 man_id = i2c_smbus_read_word_data(new_client, - LM92_REG_MAN_ID); - - if ((config & 0xe0) == 0x00 - && man_id == 0x0180) { - pr_info("lm92: Found National Semiconductor LM92 chip\n"); - kind = lm92; - } else - if (max6635_check(new_client)) { - pr_info("lm92: Found Maxim MAX6635 chip\n"); - kind = lm92; /* No separate prefix */ - } - else - goto exit_free; - } else - if (kind == 0) /* Default to an LM92 if forced */ - kind = lm92; - - /* Give it the proper name */ - if (kind == lm92) { - name = "lm92"; - } else { /* Supposedly cannot happen */ - dev_dbg(&new_client->dev, "Kind out of range?\n"); - goto exit_free; - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the i2c subsystem a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the chipset */ - lm92_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm92_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm92_detect); -} - -static int lm92_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - - -/* - * Module and driver stuff - */ - -static struct i2c_driver lm92_driver = { - .owner = THIS_MODULE, - .name = "lm92", - .id = I2C_DRIVERID_LM92, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm92_attach_adapter, - .detach_client = lm92_detach_client, -}; - -static int __init sensors_lm92_init(void) -{ - return i2c_add_driver(&lm92_driver); -} - -static void __exit sensors_lm92_exit(void) -{ - i2c_del_driver(&lm92_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM92/MAX6635 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm92_init); -module_exit(sensors_lm92_exit); diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c deleted file mode 100644 index bf553dcd97d..00000000000 --- a/drivers/i2c/chips/max1619.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * max1619.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Alexey Fisher - * Jean Delvare - * - * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. - * It reports up to two temperatures (its own plus up to - * one external one). Complete datasheet can be - * obtained from Maxim's website at: - * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include - - -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max1619); - -/* - * The MAX1619 registers - */ - -#define MAX1619_REG_R_MAN_ID 0xFE -#define MAX1619_REG_R_CHIP_ID 0xFF -#define MAX1619_REG_R_CONFIG 0x03 -#define MAX1619_REG_W_CONFIG 0x09 -#define MAX1619_REG_R_CONVRATE 0x04 -#define MAX1619_REG_W_CONVRATE 0x0A -#define MAX1619_REG_R_STATUS 0x02 -#define MAX1619_REG_R_LOCAL_TEMP 0x00 -#define MAX1619_REG_R_REMOTE_TEMP 0x01 -#define MAX1619_REG_R_REMOTE_HIGH 0x07 -#define MAX1619_REG_W_REMOTE_HIGH 0x0D -#define MAX1619_REG_R_REMOTE_LOW 0x08 -#define MAX1619_REG_W_REMOTE_LOW 0x0E -#define MAX1619_REG_R_REMOTE_CRIT 0x10 -#define MAX1619_REG_W_REMOTE_CRIT 0x12 -#define MAX1619_REG_R_TCRIT_HYST 0x11 -#define MAX1619_REG_W_TCRIT_HYST 0x13 - -/* - * Conversions and various macros - */ - -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) -#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000) - -/* - * Functions declaration - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter); -static int max1619_detect(struct i2c_adapter *adapter, int address, - int kind); -static void max1619_init_client(struct i2c_client *client); -static int max1619_detach_client(struct i2c_client *client); -static struct max1619_data *max1619_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver max1619_driver = { - .owner = THIS_MODULE, - .name = "max1619", - .flags = I2C_DF_NOTIFY, - .attach_adapter = max1619_attach_adapter, - .detach_client = max1619_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct max1619_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 temp_input1; /* local */ - u8 temp_input2, temp_low2, temp_high2; /* remote */ - u8 temp_crit2; - u8 temp_hyst2; - u8 alarms; -}; - -/* - * Sysfs stuff - */ - -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct max1619_data *data = max1619_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp_input1); -show_temp(temp_input2); -show_temp(temp_low2); -show_temp(temp_high2); -show_temp(temp_crit2); -show_temp(temp_hyst2); - -#define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct max1619_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); -set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); -set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); -set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct max1619_data *data = max1619_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, - set_temp_hyst2); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, max1619_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct max1619_data *data; - int err = 0; - const char *name = ""; - u8 reg_config=0, reg_convrate=0, reg_status=0; - u8 man_id, chip_id; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct max1619_data)); - - /* The common I2C client data is placed right before the - MAX1619-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &max1619_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - if (kind < 0) { /* detection */ - reg_config = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONFIG); - reg_convrate = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONVRATE); - reg_status = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_STATUS); - if ((reg_config & 0x03) != 0x00 - || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) { - dev_dbg(&adapter->dev, - "MAX1619 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - - man_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CHIP_ID); - - if ((man_id == 0x4D) && (chip_id == 0x04)){ - kind = max1619; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - - - if (kind == max1619){ - name = "max1619"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the MAX1619 chip */ - max1619_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void max1619_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, - 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (config & 0x40) - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, - config & 0xBF); /* run */ -} - -static int max1619_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 struct max1619_data *max1619_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Updating max1619 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->temp_input2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->temp_high2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_HIGH); - data->temp_low2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_LOW); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_CRIT); - data->temp_hyst2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_TCRIT_HYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_max1619_init(void) -{ - return i2c_add_driver(&max1619_driver); -} - -static void __exit sensors_max1619_exit(void) -{ - i2c_del_driver(&max1619_driver); -} - -MODULE_AUTHOR("Alexey Fisher and" - "Jean Delvare "); -MODULE_DESCRIPTION("MAX1619 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_max1619_init); -module_exit(sensors_max1619_exit); diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c deleted file mode 100644 index 876c68f3af3..00000000000 --- a/drivers/i2c/chips/pc87360.c +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * pc87360.c - Part of lm_sensors, Linux kernel modules - * for hardware monitoring - * Copyright (C) 2004 Jean Delvare - * - * Copied from smsc47m1.c: - * Copyright (C) 2002 Mark D. Studebaker - * - * 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. - * - * Supports the following chips: - * - * Chip #vin #fan #pwm #temp devid - * PC87360 - 2 2 - 0xE1 - * PC87363 - 2 2 - 0xE8 - * PC87364 - 3 3 - 0xE4 - * PC87365 11 3 3 2 0xE5 - * PC87366 11 3 3 3-4 0xE9 - * - * This driver assumes that no more than one chip is present, and one of - * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{ NULL }}; -static u8 devid; -static unsigned int extra_isa[3]; -static u8 confreg[4]; - -enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .forces = forces, -}; - -static int init = 1; -module_param(init, int, 0); -MODULE_PARM_DESC(init, - "Chip initialization level:\n" - " 0: None\n" - "*1: Forcibly enable internal voltage and temperature channels, except in9\n" - " 2: Forcibly enable all voltage and temperature channels, except in9\n" - " 3: Forcibly enable all voltage and temperature channels, including in9"); - -/* - * Super-I/O registers and operations - */ - -#define DEV 0x07 /* Register: Logical device select */ -#define DEVID 0x20 /* Register: Device ID */ -#define ACT 0x30 /* Register: Device activation */ -#define BASE 0x60 /* Register: Base address */ - -#define FSCM 0x09 /* Logical device: fans */ -#define VLM 0x0d /* Logical device: voltages */ -#define TMS 0x0e /* Logical device: temperatures */ -static const u8 logdev[3] = { FSCM, VLM, TMS }; - -#define LD_FAN 0 -#define LD_IN 1 -#define LD_TEMP 2 - -static inline void superio_outb(int sioaddr, int reg, int val) -{ - outb(reg, sioaddr); - outb(val, sioaddr+1); -} - -static inline int superio_inb(int sioaddr, int reg) -{ - outb(reg, sioaddr); - return inb(sioaddr+1); -} - -static inline void superio_exit(int sioaddr) -{ - outb(0x02, sioaddr); - outb(0x02, sioaddr+1); -} - -/* - * Logical devices - */ - -#define PC87360_EXTENT 0x10 -#define PC87365_REG_BANK 0x09 -#define NO_BANK 0xff - -/* - * Fan registers and conversions - */ - -/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ -#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) -#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) -#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) -#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) -#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) - -#define FAN_FROM_REG(val,div) ((val) == 0 ? 0: \ - 480000 / ((val)*(div))) -#define FAN_TO_REG(val,div) ((val) <= 100 ? 0 : \ - 480000 / ((val)*(div))) -#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) -#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) - -#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) -#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) -#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) - -#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) -static inline u8 PWM_TO_REG(int val, int inv) -{ - if (inv) - val = 255 - val; - if (val < 0) - return 0; - if (val > 255) - return 255; - return val; -} - -/* - * Voltage registers and conversions - */ - -#define PC87365_REG_IN_CONVRATE 0x07 -#define PC87365_REG_IN_CONFIG 0x08 -#define PC87365_REG_IN 0x0B -#define PC87365_REG_IN_MIN 0x0D -#define PC87365_REG_IN_MAX 0x0C -#define PC87365_REG_IN_STATUS 0x0A -#define PC87365_REG_IN_ALARMS1 0x00 -#define PC87365_REG_IN_ALARMS2 0x01 -#define PC87365_REG_VID 0x06 - -#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) -#define IN_TO_REG(val,ref) ((val) < 0 ? 0 : \ - (val)*256 >= (ref)*255 ? 255: \ - ((val) * 256 + (ref)/2) / (ref)) - -/* - * Temperature registers and conversions - */ - -#define PC87365_REG_TEMP_CONFIG 0x08 -#define PC87365_REG_TEMP 0x0B -#define PC87365_REG_TEMP_MIN 0x0D -#define PC87365_REG_TEMP_MAX 0x0C -#define PC87365_REG_TEMP_CRIT 0x0E -#define PC87365_REG_TEMP_STATUS 0x0A -#define PC87365_REG_TEMP_ALARMS 0x00 - -#define TEMP_FROM_REG(val) ((val) * 1000) -#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : \ - (val) > 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) - -/* - * Client data (each client gets its own) - */ - -struct pc87360_data { - struct i2c_client client; - struct semaphore lock; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - int address[3]; - - u8 fannr, innr, tempnr; - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_status[3]; /* Register value */ - u8 pwm[3]; /* Register value */ - u16 fan_conf; /* Configuration register values, combined */ - - u16 in_vref; /* 1 mV/bit */ - u8 in[14]; /* Register value */ - u8 in_min[14]; /* Register value */ - u8 in_max[14]; /* Register value */ - u8 in_crit[3]; /* Register value */ - u8 in_status[14]; /* Register value */ - u16 in_alarms; /* Register values, combined, masked */ - u8 vid_conf; /* Configuration register value */ - u8 vrm; - u8 vid; /* Register value */ - - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_crit[3]; /* Register value */ - u8 temp_status[3]; /* Register value */ - u8 temp_alarms; /* Register value, masked */ -}; - -/* - * Functions declaration - */ - -static int pc87360_attach_adapter(struct i2c_adapter *adapter); -static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind); -static int pc87360_detach_client(struct i2c_client *client); - -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg); -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value); -static void pc87360_init_client(struct i2c_client *client, int use_thermistors); -static struct pc87360_data *pc87360_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver pc87360_driver = { - .owner = THIS_MODULE, - .name = "pc87360", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pc87360_attach_adapter, - .detach_client = pc87360_detach_client, -}; - -/* - * Sysfs stuff - */ - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - long fan_min = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr])); - - /* If it wouldn't fit, change clock divisor */ - while (fan_min > 255 - && (data->fan_status[nr] & 0x60) != 0x60) { - fan_min >>= 1; - data->fan[nr] >>= 1; - data->fan_status[nr] += 0x20; - } - data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - - /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr), - data->fan_status[nr] & 0xF9); - up(&data->update_lock); - - return count; -} - -#define show_and_set_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \ - FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \ - FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - FAN_DIV_FROM_REG(data->fan_status[offset-1])); \ -} \ -static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \ -} \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset##_input, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \ - show_fan##offset##_status, NULL); -show_and_set_fan(1) -show_and_set_fan(2) -show_and_set_fan(3) - -#define show_and_set_pwm(offset) \ -static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - PWM_FROM_REG(data->pwm[offset-1], \ - FAN_CONFIG_INVERT(data->fan_conf, \ - offset-1))); \ -} \ -static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->pwm[offset-1] = PWM_TO_REG(val, \ - FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \ - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \ - data->pwm[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \ - show_pwm##offset, set_pwm##offset); -show_and_set_pwm(1) -show_and_set_pwm(2) -show_and_set_pwm(3) - -#define show_and_set_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", data->in_status[offset]); \ -} \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \ - data->in_min[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, \ - data->in_vref); \ - pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \ - data->in_max[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset##_input, NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - show_in##offset##_max, set_in##offset##_max); \ -static DEVICE_ATTR(in##offset##_status, S_IRUGO, \ - show_in##offset##_status, NULL); -show_and_set_in(0) -show_and_set_in(1) -show_and_set_in(2) -show_and_set_in(3) -show_and_set_in(4) -show_and_set_in(5) -show_and_set_in(6) -show_and_set_in(7) -show_and_set_in(8) -show_and_set_in(9) -show_and_set_in(10) - -#define show_and_set_therm(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", data->in_status[offset+7]); \ -} \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \ - data->in_min[offset+7]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \ - data->in_max[offset+7]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \ - data->in_crit[offset-4]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ - show_temp##offset##_crit, set_temp##offset##_crit); \ -static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ - show_temp##offset##_status, NULL); -show_and_set_therm(4) -show_and_set_therm(5) -show_and_set_therm(6) - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_alarms); -} -static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); - -#define show_and_set_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \ -}\ -static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", data->temp_status[offset-1]); \ -}\ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \ - data->temp_min[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \ - data->temp_max[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_crit[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \ - data->temp_crit[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ - show_temp##offset##_crit, set_temp##offset##_crit); \ -static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ - show_temp##offset##_status, NULL); -show_and_set_temp(1) -show_and_set_temp(2) -show_and_set_temp(3) - -static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->temp_alarms); -} -static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); - -/* - * Device detection, registration and update - */ - -static int pc87360_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pc87360_detect); -} - -static int pc87360_find(int sioaddr, u8 *devid, int *address) -{ - u16 val; - int i; - int nrdev; /* logical device count */ - - /* No superio_enter */ - - /* Identify device */ - val = superio_inb(sioaddr, DEVID); - switch (val) { - case 0xE1: /* PC87360 */ - case 0xE8: /* PC87363 */ - case 0xE4: /* PC87364 */ - nrdev = 1; - break; - case 0xE5: /* PC87365 */ - case 0xE9: /* PC87366 */ - nrdev = 3; - break; - default: - superio_exit(sioaddr); - return -ENODEV; - } - /* Remember the device id */ - *devid = val; - - for (i = 0; i < nrdev; i++) { - /* select logical device */ - superio_outb(sioaddr, DEV, logdev[i]); - - val = superio_inb(sioaddr, ACT); - if (!(val & 0x01)) { - printk(KERN_INFO "pc87360: Device 0x%02x not " - "activated\n", logdev[i]); - continue; - } - - val = (superio_inb(sioaddr, BASE) << 8) - | superio_inb(sioaddr, BASE + 1); - if (!val) { - printk(KERN_INFO "pc87360: Base address not set for " - "device 0x%02x\n", logdev[i]); - continue; - } - - address[i] = val; - - if (i==0) { /* Fans */ - confreg[0] = superio_inb(sioaddr, 0xF0); - confreg[1] = superio_inb(sioaddr, 0xF1); - -#ifdef DEBUG - printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif - } else if (i==1) { /* Voltages */ - /* Are we using thermistors? */ - if (*devid == 0xE9) { /* PC87366 */ - /* These registers are not logical-device - specific, just that we won't need them if - we don't use the VLM device */ - confreg[2] = superio_inb(sioaddr, 0x2B); - confreg[3] = superio_inb(sioaddr, 0x25); - - if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360: Using " - "thermistors for temperature " - "monitoring\n"); - } - if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); - } - } - } - } - - superio_exit(sioaddr); - return 0; -} - -/* We don't really care about the address. - Read from extra_isa instead. */ -int pc87360_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct pc87360_data *data; - int err = 0; - const char *name = "pc87360"; - int use_thermistors = 0; - - if (!i2c_is_isa_adapter(adapter)) - return -ENODEV; - - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) - return -ENOMEM; - memset(data, 0x00, sizeof(struct pc87360_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &pc87360_driver; - new_client->flags = 0; - - data->fannr = 2; - data->innr = 0; - data->tempnr = 0; - - switch (devid) { - case 0xe8: - name = "pc87363"; - break; - case 0xe4: - name = "pc87364"; - data->fannr = 3; - break; - case 0xe5: - name = "pc87365"; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 11 : 0; - data->tempnr = extra_isa[2] ? 2 : 0; - break; - case 0xe9: - name = "pc87366"; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 14 : 0; - data->tempnr = extra_isa[2] ? 3 : 0; - break; - } - - strcpy(new_client->name, name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - for (i = 0; i < 3; i++) { - if (((data->address[i] = extra_isa[i])) - && !request_region(extra_isa[i], PC87360_EXTENT, - pc87360_driver.name)) { - dev_err(&new_client->dev, "Region 0x%x-0x%x already " - "in use!\n", extra_isa[i], - extra_isa[i]+PC87360_EXTENT-1); - for (i--; i >= 0; i--) - release_region(extra_isa[i], PC87360_EXTENT); - err = -EBUSY; - goto ERROR1; - } - } - - /* Retrieve the fans configuration from Super-I/O space */ - if (data->fannr) - data->fan_conf = confreg[0] | (confreg[1] << 8); - - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Use the correct reference voltage - Unless both the VLM and the TMS logical devices agree to - use an external Vref, the internal one is used. */ - if (data->innr) { - i = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (data->tempnr) { - i &= pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - } - data->in_vref = (i&0x02) ? 3025 : 2966; - dev_dbg(&new_client->dev, "Using %s reference voltage\n", - (i&0x02) ? "external" : "internal"); - - data->vid_conf = confreg[3]; - data->vrm = 90; - } - - /* Fan clock dividers may be needed before any data is read */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - } - - if (init > 0) { - if (devid == 0xe9 && data->address[1]) /* PC87366 */ - use_thermistors = confreg[2] & 0x40; - - pc87360_init_client(new_client, use_thermistors); - } - - /* Register sysfs hooks */ - if (data->innr) { - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in8_input); - device_create_file(&new_client->dev, &dev_attr_in9_input); - device_create_file(&new_client->dev, &dev_attr_in10_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in8_min); - device_create_file(&new_client->dev, &dev_attr_in9_min); - device_create_file(&new_client->dev, &dev_attr_in10_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in7_max); - device_create_file(&new_client->dev, &dev_attr_in8_max); - device_create_file(&new_client->dev, &dev_attr_in9_max); - device_create_file(&new_client->dev, &dev_attr_in10_max); - device_create_file(&new_client->dev, &dev_attr_in0_status); - device_create_file(&new_client->dev, &dev_attr_in1_status); - device_create_file(&new_client->dev, &dev_attr_in2_status); - device_create_file(&new_client->dev, &dev_attr_in3_status); - device_create_file(&new_client->dev, &dev_attr_in4_status); - device_create_file(&new_client->dev, &dev_attr_in5_status); - device_create_file(&new_client->dev, &dev_attr_in6_status); - device_create_file(&new_client->dev, &dev_attr_in7_status); - device_create_file(&new_client->dev, &dev_attr_in8_status); - device_create_file(&new_client->dev, &dev_attr_in9_status); - device_create_file(&new_client->dev, &dev_attr_in10_status); - - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_alarms_in); - } - - if (data->tempnr) { - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_status); - device_create_file(&new_client->dev, &dev_attr_temp2_status); - - device_create_file(&new_client->dev, &dev_attr_alarms_temp); - } - if (data->tempnr == 3) { - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_status); - } - if (data->innr == 14) { - device_create_file(&new_client->dev, &dev_attr_temp4_input); - device_create_file(&new_client->dev, &dev_attr_temp5_input); - device_create_file(&new_client->dev, &dev_attr_temp6_input); - device_create_file(&new_client->dev, &dev_attr_temp4_min); - device_create_file(&new_client->dev, &dev_attr_temp5_min); - device_create_file(&new_client->dev, &dev_attr_temp6_min); - device_create_file(&new_client->dev, &dev_attr_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp5_max); - device_create_file(&new_client->dev, &dev_attr_temp6_max); - device_create_file(&new_client->dev, &dev_attr_temp4_crit); - device_create_file(&new_client->dev, &dev_attr_temp5_crit); - device_create_file(&new_client->dev, &dev_attr_temp6_crit); - device_create_file(&new_client->dev, &dev_attr_temp4_status); - device_create_file(&new_client->dev, &dev_attr_temp5_status); - device_create_file(&new_client->dev, &dev_attr_temp6_status); - } - - if (data->fannr) { - if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { - device_create_file(&new_client->dev, - &dev_attr_fan1_input); - device_create_file(&new_client->dev, - &dev_attr_fan1_min); - device_create_file(&new_client->dev, - &dev_attr_fan1_div); - device_create_file(&new_client->dev, - &dev_attr_fan1_status); - } - - if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { - device_create_file(&new_client->dev, - &dev_attr_fan2_input); - device_create_file(&new_client->dev, - &dev_attr_fan2_min); - device_create_file(&new_client->dev, - &dev_attr_fan2_div); - device_create_file(&new_client->dev, - &dev_attr_fan2_status); - } - - if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) - device_create_file(&new_client->dev, &dev_attr_pwm1); - if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) - device_create_file(&new_client->dev, &dev_attr_pwm2); - } - if (data->fannr == 3) { - if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { - device_create_file(&new_client->dev, - &dev_attr_fan3_input); - device_create_file(&new_client->dev, - &dev_attr_fan3_min); - device_create_file(&new_client->dev, - &dev_attr_fan3_div); - device_create_file(&new_client->dev, - &dev_attr_fan3_status); - } - - if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) - device_create_file(&new_client->dev, &dev_attr_pwm3); - } - - return 0; - -ERROR2: - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } -ERROR1: - kfree(data); - return err; -} - -static int pc87360_detach_client(struct i2c_client *client) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - int i; - - if ((i = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return i; - } - - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(data); - - return 0; -} - -/* ldi is the logical device index - bank is for voltages and temperatures only */ -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg) -{ - int res; - - down(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - res = inb_p(data->address[ldi] + reg); - up(&(data->lock)); - - return res; -} - -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value) -{ - down(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - outb_p(value, data->address[ldi] + reg); - up(&(data->lock)); -} - -static void pc87360_init_client(struct i2c_client *client, int use_thermistors) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - int i, nr; - const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; - const u8 init_temp[3] = { 2, 2, 1 }; - u8 reg; - - if (init >= 2 && data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE); - dev_info(&client->dev, "VLM conversion set to" - "1s period, 160us delay\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE, - (reg & 0xC0) | 0x11); - } - - nr = data->innr < 11 ? data->innr : 11; - for (i=0; i= init_in[i]) { - /* Forcibly enable voltage channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling in%d\n", i); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - (reg & 0x68) | 0x87); - } - } - } - - /* We can't blindly trust the Super-I/O space configuration bit, - most BIOS won't set it properly */ - for (i=11; iinnr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS); - use_thermistors = use_thermistors || (reg & 0x01); - } - - i = use_thermistors ? 2 : 0; - for (; itempnr; i++) { - if (init >= init_temp[i]) { - /* Forcibly enable temperature channel */ - reg = pc87360_read_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling temp%d\n", i+1); - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - 0xCF); - } - } - } - - if (use_thermistors) { - for (i=11; iinnr; i++) { - if (init >= init_in[i]) { - /* The pin may already be used by thermal - diodes */ - reg = pc87360_read_value(data, LD_TEMP, - (i-11)/2, PC87365_REG_TEMP_STATUS); - if (reg & 0x01) { - dev_dbg(&client->dev, "Skipping " - "temp%d, pin already in use " - "by temp%d\n", i-7, (i-11)/2); - continue; - } - - /* Forcibly enable thermistor channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling temp%d\n", i-7); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS, - (reg & 0x60) | 0x8F); - } - } - } - } - - if (data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (reg & 0x01) { - dev_dbg(&client->dev, "Forcibly " - "enabling monitoring (VLM)\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG, - reg & 0xFE); - } - } - - if (data->tempnr) { - reg = pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - if (reg & 0x01) { - dev_dbg(&client->dev, "Forcibly enabling " - "monitoring (TMS)\n"); - pc87360_write_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG, - reg & 0xFE); - } - - if (init >= 2) { - /* Chip config as documented by National Semi. */ - pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* We voluntarily omit the bank here, in case the - sequence itself matters. It shouldn't be a problem, - since nobody else is supposed to access the - device at that point. */ - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); - } - } -} - -static void pc87360_autodiv(struct i2c_client *client, int nr) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - u8 old_min = data->fan_min[nr]; - - /* Increase clock divider if needed and possible */ - if ((data->fan_status[nr] & 0x04) /* overflow flag */ - || (data->fan[nr] >= 224)) { /* next to overflow */ - if ((data->fan_status[nr] & 0x60) != 0x60) { - data->fan_status[nr] += 0x20; - data->fan_min[nr] >>= 1; - data->fan[nr] >>= 1; - dev_dbg(&client->dev, "Increasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); - } - } else { - /* Decrease clock divider if possible */ - while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ - && data->fan[nr] < 85 /* bad accuracy */ - && (data->fan_status[nr] & 0x60) != 0x00) { - data->fan_status[nr] -= 0x20; - data->fan_min[nr] <<= 1; - data->fan[nr] <<= 1; - dev_dbg(&client->dev, "Decreasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); - } - } - - /* Write new fan min if it changed */ - if (old_min != data->fan_min[nr]) { - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - } -} - -static struct pc87360_data *pc87360_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - u8 i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Data update\n"); - - /* Fans */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - data->fan_status[i] = - pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN_STATUS(i)); - data->fan[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN(i)); - data->fan_min[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(i)); - /* Change clock divider if needed */ - pc87360_autodiv(client, i); - /* Clear bits and write new divider */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i), - data->fan_status[i]); - } - if (FAN_CONFIG_CONTROL(data->fan_conf, i)) - data->pwm[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_PWM(i)); - } - - /* Voltages */ - for (i = 0; i < data->innr; i++) { - data->in_status[i] = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - data->in_status[i]); - if ((data->in_status[i] & 0x81) == 0x81) { - data->in[i] = pc87360_read_value(data, LD_IN, - i, PC87365_REG_IN); - } - if (data->in_status[i] & 0x01) { - data->in_min[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MIN); - data->in_max[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MAX); - if (i >= 11) - data->in_crit[i-11] = - pc87360_read_value(data, LD_IN, - i, PC87365_REG_TEMP_CRIT); - } - } - if (data->innr) { - data->in_alarms = pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS1) - | ((pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS2) - & 0x07) << 8); - data->vid = (data->vid_conf & 0xE0) ? - pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_VID) : 0x1F; - } - - /* Temperatures */ - for (i = 0; i < data->tempnr; i++) { - data->temp_status[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - data->temp_status[i]); - if ((data->temp_status[i] & 0x81) == 0x81) { - data->temp[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP); - } - if (data->temp_status[i] & 0x01) { - data->temp_min[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MIN); - data->temp_max[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MAX); - data->temp_crit[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_CRIT); - } - } - if (data->tempnr) { - data->temp_alarms = pc87360_read_value(data, LD_TEMP, - NO_BANK, PC87365_REG_TEMP_ALARMS) - & 0x3F; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init pc87360_init(void) -{ - int i; - - if (pc87360_find(0x2e, &devid, extra_isa) - && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360: PC8736x not detected, " - "module not inserted.\n"); - return -ENODEV; - } - - /* Arbitrarily pick one of the addresses */ - for (i = 0; i < 3; i++) { - if (extra_isa[i] != 0x0000) { - normal_isa[0] = extra_isa[i]; - break; - } - } - - if (normal_isa[0] == 0x0000) { - printk(KERN_WARNING "pc87360: No active logical device, " - "module not inserted.\n"); - return -ENODEV; - } - - return i2c_add_driver(&pc87360_driver); -} - -static void __exit pc87360_exit(void) -{ - i2c_del_driver(&pc87360_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PC8736x hardware monitor"); -MODULE_LICENSE("GPL"); - -module_init(pc87360_init); -module_exit(pc87360_exit); diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c deleted file mode 100644 index 6bbfc8fb4f1..00000000000 --- a/drivers/i2c/chips/sis5595.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - sis5595.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (C) 1998 - 2001 Frodo Looijaard , - Kyösti Mälkki , and - Mark D. Studebaker - Ported to Linux 2.6 by Aurelien Jarno with - the help of Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SiS southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 AF or less - 2 1039/0008 B0 or greater - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static u16 force_addr; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(sis5595); - -/* Many SIS5595 constants specified below */ - -/* Length of ISA address segment */ -#define SIS5595_EXTENT 8 -/* PCI Config Registers */ -#define SIS5595_REVISION_REG 0x08 -#define SIS5595_BASE_REG 0x68 -#define SIS5595_PIN_REG 0x7A -#define SIS5595_ENABLE_REG 0x7B - -/* Where are the ISA address/data registers relative to the base address */ -#define SIS5595_ADDR_REG_OFFSET 5 -#define SIS5595_DATA_REG_OFFSET 6 - -/* The SIS5595 registers */ -#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define SIS5595_REG_IN(nr) (0x20 + (nr)) - -#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) -#define SIS5595_REG_FAN(nr) (0x28 + (nr)) - -/* On the first version of the chip, the temp registers are separate. - On the second version, - TEMP pin is shared with IN4, configured in PCI register 0x7A. - The registers are the same as well. - OVER and HYST are really MAX and MIN. */ - -#define REV2MIN 0xb0 -#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN(4) : 0x27 -#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MAX(4) : 0x39 -#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MIN(4) : 0x3a - -#define SIS5595_REG_CONFIG 0x40 -#define SIS5595_REG_ALARM1 0x41 -#define SIS5595_REG_ALARM2 0x42 -#define SIS5595_REG_FANDIV 0x47 - -/* Conversions. Limit checking is only done on the TO_REG - variants. */ - -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ -static inline u8 IN_TO_REG(unsigned long val) -{ - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); - return (nval + 8) / 16; -} -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static inline int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* TEMP: mC (-54.12C to +157.53C) - REG: 0.83C/bit + 52.12, two's complement */ -static inline int TEMP_FROM_REG(s8 val) -{ - return val * 830 + 52120; -} -static inline s8 TEMP_TO_REG(int val) -{ - int nval = SENSORS_LIMIT(val, -54120, 157530) ; - return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; -} - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static inline u8 DIV_TO_REG(int val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} -#define DIV_FROM_REG(val) (1 << (val)) - -/* For the SIS5595, we need to keep some data in memory. That - data is pointed to by sis5595_list[NR]->data. The structure itself is - dynamically allocated, at the time when the new sis5595 client is - allocated. */ -struct sis5595_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - char maxins; /* == 3 if temp enabled, otherwise == 4 */ - u8 revision; /* Reg. value */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ - -static int sis5595_attach_adapter(struct i2c_adapter *adapter); -static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind); -static int sis5595_detach_client(struct i2c_client *client); - -static int sis5595_read_value(struct i2c_client *client, u8 register); -static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value); -static struct sis5595_data *sis5595_update_device(struct device *dev); -static void sis5595_init_client(struct i2c_client *client); - -static struct i2c_driver sis5595_driver = { - .owner = THIS_MODULE, - .name = "sis5595", - .id = I2C_DRIVERID_SIS5595, - .flags = I2C_DF_NOTIFY, - .attach_adapter = sis5595_attach_adapter, - .detach_client = sis5595_detach_client, -}; - -/* 4 Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); - -/* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over = TEMP_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = TEMP_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); - -/* 2 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); - int reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - reg = sis5595_read_value(client, SIS5595_REG_FANDIV); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - switch (nr) { - case 0: - reg = (reg & 0xcf) | (data->fan_div[nr] << 4); - break; - case 1: - reg = (reg & 0x3f) | (data->fan_div[nr] << 6); - break; - } - sis5595_write_value(client, SIS5595_REG_FANDIV, reg); - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); - -static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 0) ; -} - -static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 1) ; -} -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div); -static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* This is called when the module is loaded */ -static int sis5595_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, sis5595_detect); -} - -int sis5595_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int err = 0; - int i; - struct i2c_client *new_client; - struct sis5595_data *data; - char val; - u16 a; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) - goto exit; - - if (force_addr) - address = force_addr & ~(SIS5595_EXTENT - 1); - /* Reserve the ISA region */ - if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { - err = -EBUSY; - goto exit; - } - if (force_addr) { - dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) - goto exit_release; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) - goto exit_release; - if ((a & ~(SIS5595_EXTENT - 1)) != address) - /* doesn't work for some chips? */ - goto exit_release; - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { - goto exit_release; - } - if ((val & 0x80) == 0) { - if (PCIBIOS_SUCCESSFUL != - pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, - val | 0x80)) - goto exit_release; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - goto exit_release; - if ((val & 0x80) == 0) - /* doesn't work for some chips! */ - goto exit_release; - } - - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct sis5595_data)); - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->adapter = adapter; - new_client->driver = &sis5595_driver; - new_client->flags = 0; - - /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); - /* 4 voltages, 1 temp */ - data->maxins = 3; - if (data->revision >= REV2MIN) { - pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); - if (!(val & 0x80)) - /* 5 voltages, no temps */ - data->maxins = 4; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the SIS5595 chip */ - sis5595_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 2; i++) { - data->fan_min[i] = sis5595_read_value(new_client, - SIS5595_REG_FAN_MIN(i)); - } - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - if (data->maxins == 4) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - } - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - if (data->maxins == 3) { - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - } - return 0; - -exit_free: - kfree(data); -exit_release: - release_region(address, SIS5595_EXTENT); -exit: - return err; -} - -static int sis5595_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if (i2c_is_isa_client(client)) - release_region(client->addr, SIS5595_EXTENT); - - kfree(i2c_get_clientdata(client)); - - return 0; -} - - -/* ISA access must be locked explicitly. */ -static int sis5595_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - struct sis5595_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); - up(&data->lock); - return res; -} - -static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - struct sis5595_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); - up(&data->lock); - return 0; -} - -/* Called when we have found a new SIS5595. */ -static void sis5595_init_client(struct i2c_client *client) -{ - u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); - if (!(config & 0x01)) - sis5595_write_value(client, SIS5595_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static struct sis5595_data *sis5595_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - for (i = 0; i <= data->maxins; i++) { - data->in[i] = - sis5595_read_value(client, SIS5595_REG_IN(i)); - data->in_min[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MIN(i)); - data->in_max[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) { - data->fan[i] = - sis5595_read_value(client, SIS5595_REG_FAN(i)); - data->fan_min[i] = - sis5595_read_value(client, - SIS5595_REG_FAN_MIN(i)); - } - if (data->maxins == 3) { - data->temp = - sis5595_read_value(client, SIS5595_REG_TEMP); - data->temp_over = - sis5595_read_value(client, SIS5595_REG_TEMP_OVER); - data->temp_hyst = - sis5595_read_value(client, SIS5595_REG_TEMP_HYST); - } - i = sis5595_read_value(client, SIS5595_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - sis5595_read_value(client, SIS5595_REG_ALARM1) | - (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static struct pci_device_id sis5595_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); - -static int blacklist[] __devinitdata = { - PCI_DEVICE_ID_SI_540, - PCI_DEVICE_ID_SI_550, - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_645, - PCI_DEVICE_ID_SI_730, - PCI_DEVICE_ID_SI_735, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ - PCI_DEVICE_ID_SI_5597, - PCI_DEVICE_ID_SI_5598, - 0 }; - -static int __devinit sis5595_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int *i; - int addr = 0; - - for (i = blacklist; *i != 0; i++) { - struct pci_dev *dev; - dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); - if (dev) { - dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); - pci_dev_put(dev); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, SIS5595_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(SIS5595_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - s_bridge = pci_dev_get(dev); - if (i2c_add_driver(&sis5595_driver)) { - pci_dev_put(s_bridge); - s_bridge = NULL; - } - - /* Always return failure here. This is to allow other drivers to bind - * to this pci device. We don't really want to have control over the - * pci device, we only wanted to read as few register values from it. - */ - return -ENODEV; -} - -static struct pci_driver sis5595_pci_driver = { - .name = "sis5595", - .id_table = sis5595_pci_ids, - .probe = sis5595_pci_probe, -}; - -static int __init sm_sis5595_init(void) -{ - return pci_register_driver(&sis5595_pci_driver); -} - -static void __exit sm_sis5595_exit(void) -{ - pci_unregister_driver(&sis5595_pci_driver); - if (s_bridge != NULL) { - i2c_del_driver(&sis5595_driver); - pci_dev_put(s_bridge); - s_bridge = NULL; - } -} - -MODULE_AUTHOR("Aurelien Jarno "); -MODULE_DESCRIPTION("SiS 5595 Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_sis5595_init); -module_exit(sm_sis5595_exit); diff --git a/drivers/i2c/chips/smsc47b397.c b/drivers/i2c/chips/smsc47b397.c deleted file mode 100644 index 251ac265955..00000000000 --- a/drivers/i2c/chips/smsc47b397.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - smsc47b397.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B397-NC Super-I/O chip. - - Author/Maintainer: Mark M. Hoffman - Copyright (C) 2004 Utilitek Systems, Inc. - - derived in part from smsc47m1.c: - Copyright (C) 2002 Mark D. Studebaker - Copyright (C) 2004 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -/* Address is autodetected, there is no default value */ -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; - -enum chips { any_chip, smsc47b397 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .probe = normal_i2c, /* cheat */ - .ignore = normal_i2c, /* cheat */ - .forces = forces, -}; - -/* Super-I/0 registers and commands */ - -#define REG 0x2e /* The register to read/write */ -#define VAL 0x2f /* The value to read/write */ - -static inline void superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -/* select superio logical device */ -static inline void superio_select(int ld) -{ - superio_outb(0x07, ld); -} - -static inline void superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void superio_exit(void) -{ - outb(0xAA, REG); -} - -#define SUPERIO_REG_DEVID 0x20 -#define SUPERIO_REG_DEVREV 0x21 -#define SUPERIO_REG_BASE_MSB 0x60 -#define SUPERIO_REG_BASE_LSB 0x61 -#define SUPERIO_REG_LD8 0x08 - -#define SMSC_EXTENT 0x02 - -/* 0 <= nr <= 3 */ -static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; -#define SMSC47B397_REG_TEMP(nr) (smsc47b397_reg_temp[(nr)]) - -/* 0 <= nr <= 3 */ -#define SMSC47B397_REG_FAN_LSB(nr) (0x28 + 2 * (nr)) -#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) - -struct smsc47b397_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - unsigned long last_updated; /* in jiffies */ - int valid; - - /* register values */ - u16 fan[4]; - u8 temp[4]; -}; - -static int smsc47b397_read_value(struct i2c_client *client, u8 reg) -{ - struct smsc47b397_data *data = i2c_get_clientdata(client); - int res; - - down(&data->lock); - outb(reg, client->addr); - res = inb_p(client->addr + 1); - up(&data->lock); - return res; -} - -static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47b397_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - dev_dbg(&client->dev, "starting device update...\n"); - - /* 4 temperature inputs, 4 fan inputs */ - for (i = 0; i < 4; i++) { - data->temp[i] = smsc47b397_read_value(client, - SMSC47B397_REG_TEMP(i)); - - /* must read LSB first */ - data->fan[i] = smsc47b397_read_value(client, - SMSC47B397_REG_FAN_LSB(i)); - data->fan[i] |= smsc47b397_read_value(client, - SMSC47B397_REG_FAN_MSB(i)) << 8; - } - - data->last_updated = jiffies; - data->valid = 1; - - dev_dbg(&client->dev, "... device update complete\n"); - } - - up(&data->update_lock); - - return data; -} - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static int temp_from_reg(u8 reg) -{ - return (s8)reg * 1000; -} - -/* 0 <= nr <= 3 */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); -} - -#define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) - -sysfs_temp(1); -sysfs_temp(2); -sysfs_temp(3); -sysfs_temp(4); - -#define device_create_file_temp(client, num) \ - device_create_file(&client->dev, &dev_attr_temp##num##_input) - -/* FAN: 1 RPM/bit - REG: count of 90kHz pulses / revolution */ -static int fan_from_reg(u16 reg) -{ - return 90000 * 60 / reg; -} - -/* 0 <= nr <= 3 */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); -} - -#define sysfs_fan(num) \ -static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) - -sysfs_fan(1); -sysfs_fan(2); -sysfs_fan(3); -sysfs_fan(4); - -#define device_create_file_fan(client, num) \ - device_create_file(&client->dev, &dev_attr_fan##num##_input) - -static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind); - -static int smsc47b397_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, smsc47b397_detect); -} - -static int smsc47b397_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; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static struct i2c_driver smsc47b397_driver = { - .owner = THIS_MODULE, - .name = "smsc47b397", - .id = I2C_DRIVERID_SMSC47B397, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47b397_attach_adapter, - .detach_client = smsc47b397_detach_client, -}; - -static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind) -{ - struct i2c_client *new_client; - struct smsc47b397_data *data; - int err = 0; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr); - return -EBUSY; - } - - if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error_release; - } - memset(data, 0x00, sizeof(struct smsc47b397_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = addr; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47b397_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE); - - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto error_free; - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - device_create_file_fan(new_client, 4); - - return 0; - -error_free: - kfree(new_client); -error_release: - release_region(addr, SMSC_EXTENT); - return err; -} - -static int __init smsc47b397_find(unsigned int *addr) -{ - u8 id, rev; - - superio_enter(); - id = superio_inb(SUPERIO_REG_DEVID); - - if (id != 0x6f) { - superio_exit(); - return -ENODEV; - } - - rev = superio_inb(SUPERIO_REG_DEVREV); - - superio_select(SUPERIO_REG_LD8); - *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) - | superio_inb(SUPERIO_REG_BASE_LSB); - - printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " - "(base address 0x%04x, revision %u)\n", *addr, rev); - - superio_exit(); - return 0; -} - -static int __init smsc47b397_init(void) -{ - int ret; - - if ((ret = smsc47b397_find(normal_isa))) - return ret; - - return i2c_add_driver(&smsc47b397_driver); -} - -static void __exit smsc47b397_exit(void) -{ - i2c_del_driver(&smsc47b397_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("SMSC LPC47B397 driver"); -MODULE_LICENSE("GPL"); - -module_init(smsc47b397_init); -module_exit(smsc47b397_exit); diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c deleted file mode 100644 index 897117a7213..00000000000 --- a/drivers/i2c/chips/smsc47m1.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - smsc47m1.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x - Super-I/O chips. - - Copyright (C) 2002 Mark D. Studebaker - Copyright (C) 2004 Jean Delvare - Ported to Linux 2.6 by Gabriele Gorla - and Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -/* Address is autodetected, there is no default value */ -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; - -enum chips { any_chip, smsc47m1 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .forces = forces, -}; - -/* Super-I/0 registers and commands */ - -#define REG 0x2e /* The register to read/write */ -#define VAL 0x2f /* The value to read/write */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -/* logical device for fans is 0x0A */ -#define superio_select() superio_outb(0x07, 0x0A) - -static inline void -superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define SUPERIO_REG_ACT 0x30 -#define SUPERIO_REG_BASE 0x60 -#define SUPERIO_REG_DEVID 0x20 - -/* Logical device registers */ - -#define SMSC_EXTENT 0x80 - -/* nr is 0 or 1 in the macros below */ -#define SMSC47M1_REG_ALARM 0x04 -#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) -#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) -#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) -#define SMSC47M1_REG_FANDIV 0x58 -#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) -#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) - -#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ - 983040/((192-(reg))*(div))) -#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ - 983040/(((reg)-(preload))*(div))) -#define DIV_FROM_REG(reg) (1 << (reg)) -#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) -#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) -#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) - -struct smsc47m1_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - u8 fan[2]; /* Register value */ - u8 fan_preload[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value (bit 7 is enable) */ -}; - - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); -static int smsc47m1_find(int *address); -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); -static int smsc47m1_detach_client(struct i2c_client *client); - -static int smsc47m1_read_value(struct i2c_client *client, u8 reg); -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); - -static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, - int init); - - -static struct i2c_driver smsc47m1_driver = { - .owner = THIS_MODULE, - .name = "smsc47m1", - .id = I2C_DRIVERID_SMSC47M1, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47m1_attach_adapter, - .detach_client = smsc47m1_detach_client, -}; - -/* nr is 0 or 1 in the callback functions below */ - -static ssize_t get_fan(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - /* This chip (stupidly) stops monitoring fan speed if PWM is - enabled and duty cycle is 0%. This is fine if the monitoring - and control concern the same fan, but troublesome if they are - not (which could as well happen). */ - int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]), - data->fan_preload[nr]); - return sprintf(buf, "%d\n", rpm); -} - -static ssize_t get_fan_min(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - int rpm = MIN_FROM_REG(data->fan_preload[nr], - DIV_FROM_REG(data->fan_div[nr])); - return sprintf(buf, "%d\n", rpm); -} - -static ssize_t get_fan_div(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} - -static ssize_t get_pwm(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); -} - -static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); -} - -static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", data->alarms); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - long rpmdiv, val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); - - if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { - up(&data->update_lock); - return -EINVAL; - } - - data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), - data->fan_preload[nr]); - up(&data->update_lock); - - return count; -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long new_div = simple_strtol(buf, NULL, 10), tmp; - u8 old_div = DIV_FROM_REG(data->fan_div[nr]); - - if (new_div == old_div) /* No change */ - return count; - - down(&data->update_lock); - switch (new_div) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - up(&data->update_lock); - return -EINVAL; - } - - tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; - tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); - smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); - - /* Preserve fan min */ - tmp = 192 - (old_div * (192 - data->fan_preload[nr]) - + new_div / 2) / new_div; - data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), - data->fan_preload[nr]); - up(&data->update_lock); - - return count; -} - -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long val = simple_strtol(buf, NULL, 10); - - if (val < 0 || val > 255) - return -EINVAL; - - down(&data->update_lock); - data->pwm[nr] &= 0x81; /* Preserve additional bits */ - data->pwm[nr] |= PWM_TO_REG(val); - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), - data->pwm[nr]); - up(&data->update_lock); - - return count; -} - -static ssize_t set_pwm_en(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long val = simple_strtol(buf, NULL, 10); - - if (val != 0 && val != 1) - return -EINVAL; - - down(&data->update_lock); - data->pwm[nr] &= 0xFE; /* preserve the other bits */ - data->pwm[nr] |= !val; - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), - data->pwm[nr]); - up(&data->update_lock); - - return count; -} - -#define fan_present(offset) \ -static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan(dev, buf, offset - 1); \ -} \ -static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm_en(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_en(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - get_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - get_fan##offset##_div, set_fan##offset##_div); \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - get_pwm##offset, set_pwm##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - get_pwm##offset##_en, set_pwm##offset##_en); - -fan_present(1); -fan_present(2); - -static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, smsc47m1_detect); -} - -static int smsc47m1_find(int *address) -{ - u8 val; - - superio_enter(); - val = superio_inb(SUPERIO_REG_DEVID); - - /* - * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id - * 0x5F) and LPC47B27x (device id 0x51) have fan control. - * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60). - */ - if (val == 0x51) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); - else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); - else if (val == 0x5F) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); - else if (val == 0x60) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); - else { - superio_exit(); - return -ENODEV; - } - - superio_select(); - *address = (superio_inb(SUPERIO_REG_BASE) << 8) - | superio_inb(SUPERIO_REG_BASE + 1); - val = superio_inb(SUPERIO_REG_ACT); - if (*address == 0 || (val & 0x01) == 0) { - printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); - superio_exit(); - return -ENODEV; - } - - superio_exit(); - return 0; -} - -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct smsc47m1_data *data; - int err = 0; - int fan1, fan2, pwm1, pwm2; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); - return -EBUSY; - } - - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error_release; - } - memset(data, 0x00, sizeof(struct smsc47m1_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47m1_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); - init_MUTEX(&data->update_lock); - - /* If no function is properly configured, there's no point in - actually registering the chip. */ - fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) - == 0x05; - fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) - == 0x05; - pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) - == 0x04; - pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) - == 0x04; - if (!(fan1 || fan2 || pwm1 || pwm2)) { - dev_warn(&new_client->dev, "Device is not configured, will not use\n"); - err = -ENODEV; - goto error_free; - } - - if ((err = i2c_attach_client(new_client))) - goto error_free; - - /* Some values (fan min, clock dividers, pwm registers) may be - needed before any update is triggered, so we better read them - at least once here. We don't usually do it that way, but in - this particular case, manually reading 5 registers out of 8 - doesn't make much sense and we're better using the existing - function. */ - smsc47m1_update_device(&new_client->dev, 1); - - if (fan1) { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - } else - dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " - "skipping\n"); - - if (fan2) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - } else - dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " - "skipping\n"); - - if (pwm1) { - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - } else - dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " - "skipping\n"); - if (pwm2) { - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - } else - dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " - "skipping\n"); - - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error_free: - kfree(new_client); -error_release: - release_region(address, SMSC_EXTENT); - return err; -} - -static int smsc47m1_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; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static int smsc47m1_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - res = inb_p(client->addr + reg); - up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - return res; -} - -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - outb_p(value, client->addr + reg); - up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); -} - -static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, - int init) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { - int i; - - for (i = 0; i < 2; i++) { - data->fan[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN(i)); - data->fan_preload[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN_PRELOAD(i)); - data->pwm[i] = smsc47m1_read_value(client, - SMSC47M1_REG_PWM(i)); - } - - i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - - data->alarms = smsc47m1_read_value(client, - SMSC47M1_REG_ALARM) >> 6; - /* Clear alarms if needed */ - if (data->alarms) - smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); - - data->last_updated = jiffies; - } - - up(&data->update_lock); - return data; -} - -static int __init sm_smsc47m1_init(void) -{ - if (smsc47m1_find(normal_isa)) { - return -ENODEV; - } - - return i2c_add_driver(&smsc47m1_driver); -} - -static void __exit sm_smsc47m1_exit(void) -{ - i2c_del_driver(&smsc47m1_driver); -} - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smsc47m1_init); -module_exit(sm_smsc47m1_exit); diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c deleted file mode 100644 index 164d4794839..00000000000 --- a/drivers/i2c/chips/via686a.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , - Mark Studebaker , - and Bob Dougherty - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew - and Alex van Kaam .) - - 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. -*/ - -/* - Supports the Via VT82C686A, VT82C686B south bridges. - Reports all as a 686A. - Warning - only supports a single device. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static unsigned short force_addr = 0; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(via686a); - -/* - The Via 686a southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c -*/ - -/* Many VIA686A constants specified below */ - -/* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* The VIA686A registers */ -/* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) - -/* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) - -/* temps numbered 1-3 */ -static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; -static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; -static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; -/* bits 7-6 */ -#define VIA686A_REG_TEMP_LOW1 0x4b -/* 2 = bits 5-4, 3 = bits 7-6 */ -#define VIA686A_REG_TEMP_LOW23 0x49 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -/* The following register sets temp interrupt mode (bits 1-0 for temp1, - 3-2 for temp2, 5-4 for temp3). Modes are: - 00 interrupt stays as long as value is out-of-range - 01 interrupt is cleared once register is read (default) - 10 comparator mode- like 00, but ignores hysteresis - 11 same as 00 */ -#define VIA686A_REG_TEMP_MODE 0x4b -/* We'll just assume that you want to set all 3 simultaneously: */ -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 - -/* Conversions. Limit checking is only done on the TO_REG - variants. - -********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** - From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): - voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp - voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V - voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V - voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V - voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V - in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; - That is: - volts = (25*regVal+133)*factor - regVal = (volts/factor-133)/25 - (These conversions were contributed by Jonathan Teh Soon Yew - ) */ -static inline u8 IN_TO_REG(long val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - Rounding is done (120500 is actually 133000 - 12500). - Remember that val is expressed in 0.001V/bit, which is why we divide - by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) - for the constants. */ - if (inNum <= 1) - return (u8) - SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); - else if (inNum == 2) - return (u8) - SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); - else if (inNum == 3) - return (u8) - SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); - else - return (u8) - SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); -} - -static inline long IN_FROM_REG(u8 val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - We also multiply them by 1000 because we want 0.001V/bit for the - output value. Rounding is done. */ - if (inNum <= 1) - return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); - else if (inNum == 2) - return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); - else if (inNum == 3) - return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); - else - return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); -} - -/********* FAN RPM CONVERSIONS ********/ -/* Higher register values = slower fans (the fan's strobe gates a counter). - But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) - -/******** TEMP CONVERSIONS (Bob Dougherty) *********/ -/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) - if(temp<169) - return double(temp)*0.427-32.08; - else if(temp>=169 && temp<=202) - return double(temp)*0.582-58.16; - else - return double(temp)*0.924-127.33; - - A fifth-order polynomial fits the unofficial data (provided by Alex van - Kaam ) a bit better. It also give more reasonable - numbers on my machine (ie. they agree with what my BIOS tells me). - Here's the fifth-order fit to the 8-bit data: - temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. - - (2000-10-25- RFD: thanks to Uwe Andersen for - finding my typos in this formula!) - - Alas, none of the elegant function-fit solutions will work because we - aren't allowed to use floating point in the kernel and doing it with - integers doesn't provide enough precision. So we'll do boring old - look-up table stuff. The unofficial data (see below) have effectively - 7-bit resolution (they are rounded to the nearest degree). I'm assuming - that the transfer function of the device is monotonic and smooth, so a - smooth function fit to the data will allow us to get better precision. - I used the 5th-order poly fit described above and solved for - VIA register values 0-255. I *10 before rounding, so we get tenth-degree - precision. (I could have done all 1024 values for our 10-bit readings, - but the function is very linear in the useful range (0-80 deg C), so - we'll just use linear interpolation for 10-bit readings.) So, tempLUT - is the temp at via register values 0-255: */ -static const long tempLUT[] = -{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 -}; - -/* the original LUT values from Alex van Kaam - (for via register values 12-240): -{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, --30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, --15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, --3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, -12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, -22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, -33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, -45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, -61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, -85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; - - - Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed - an extra term for a good fit to these inverse data!) and then - solving for each temp value from -50 to 110 (the useable range for - this chip). Here's the fit: - viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 - - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) - Note that n=161: */ -static const u8 viaLUT[] = -{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 -}; - -/* Converting temps to (8-bit) hyst and over registers - No interpolation here. - The +50 is because the temps start at -50 */ -static inline u8 TEMP_TO_REG(long val) -{ - return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : - (val < 0 ? val - 500 : val + 500) / 1000 + 50]; -} - -/* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) - -/* for 10-bit temperature readings */ -static inline long TEMP_FROM_REG10(u16 val) -{ - u16 eightBits = val >> 2; - u16 twoBits = val & 3; - - /* no interpolation for these */ - if (twoBits == 0 || eightBits == 255) - return TEMP_FROM_REG(eightBits); - - /* do some linear interpolation */ - return (tempLUT[eightBits] * (4 - twoBits) + - tempLUT[eightBits + 1] * twoBits) * 25; -} - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the VIA686A, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - via686a client is allocated. */ -struct via686a_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u16 temp[3]; /* Register value 10 bit */ - u8 temp_over[3]; /* Register value */ - u8 temp_hyst[3]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ - -static int via686a_attach_adapter(struct i2c_adapter *adapter); -static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); -static int via686a_detach_client(struct i2c_client *client); - -static inline int via686a_read_value(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void via686a_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -static struct via686a_data *via686a_update_device(struct device *dev); -static void via686a_init_client(struct i2c_client *client); - -/* following are the sysfs callback functions */ - -/* 7 voltage sensors */ -static ssize_t show_in(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), - data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), - data->in_max[nr]); - up(&data->update_lock); - return count; -} -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); - -/* 3 temperatures */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); -} -static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); -} -static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); -} -static ssize_t set_temp_over(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], - data->temp_over[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_temp_hyst(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], - data->temp_hyst[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_over(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_hyst(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_over(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_hyst(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_over, set_temp_##offset##_over); \ -static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_hyst, set_temp_##offset##_hyst); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -/* 2 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", - FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); -} -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int old; - - down(&data->update_lock); - old = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[nr] = DIV_TO_REG(val); - old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); - via686a_write_value(client, VIA686A_REG_FANDIV, old); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); - -show_fan_offset(1); -show_fan_offset(2); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver via686a_driver = { - .owner = THIS_MODULE, - .name = "via686a", - .id = I2C_DRIVERID_VIA686A, - .flags = I2C_DF_NOTIFY, - .attach_adapter = via686a_attach_adapter, - .detach_client = via686a_detach_client, -}; - - -/* This is called when the module is loaded */ -static int via686a_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, via686a_detect); -} - -static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct via686a_data *data; - int err = 0; - const char client_name[] = "via686a"; - u16 val; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - dev_err(&adapter->dev, - "via686a_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if (force_addr) - address = force_addr & 0xFF00; - - if (force_addr) { - dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", - address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - dev_warn(&adapter->dev, "enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - /* Reserve the ISA region */ - if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { - dev_err(&adapter->dev, "region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct via686a_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &via686a_driver; - new_client->flags = 0; - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, 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 ERROR3; - - /* Initialize the VIA686A chip */ - via686a_init_client(new_client); - - /* Register sysfs hooks */ - 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_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -ERROR3: - kfree(data); -ERROR0: - release_region(address, VIA686A_EXTENT); - return err; -} - -static int via686a_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; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* Called when we have found a new VIA686A. Set limits, etc. */ -static void via686a_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = via686a_read_value(client, VIA686A_REG_CONFIG); - via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); - - /* Configure temp interrupt mode for continuous-interrupt operation */ - via686a_write_value(client, VIA686A_REG_TEMP_MODE, - via686a_read_value(client, VIA686A_REG_TEMP_MODE) & - !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); -} - -static struct via686a_data *via686a_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 4; i++) { - data->in[i] = - via686a_read_value(client, VIA686A_REG_IN(i)); - data->in_min[i] = via686a_read_value(client, - VIA686A_REG_IN_MIN - (i)); - data->in_max[i] = - via686a_read_value(client, VIA686A_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - via686a_read_value(client, VIA686A_REG_FAN(i)); - data->fan_min[i - 1] = via686a_read_value(client, - VIA686A_REG_FAN_MIN(i)); - } - for (i = 0; i <= 2; i++) { - data->temp[i] = via686a_read_value(client, - VIA686A_REG_TEMP[i]) << 2; - data->temp_over[i] = - via686a_read_value(client, - VIA686A_REG_TEMP_OVER[i]); - data->temp_hyst[i] = - via686a_read_value(client, - VIA686A_REG_TEMP_HYST[i]); - } - /* add in lower 2 bits - temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 - */ - data->temp[0] |= (via686a_read_value(client, - VIA686A_REG_TEMP_LOW1) - & 0xc0) >> 6; - data->temp[1] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0x30) >> 4; - data->temp[2] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0xc0) >> 6; - - i = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - via686a_read_value(client, - VIA686A_REG_ALARM1) | - (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static struct pci_device_id via686a_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, via686a_pci_ids); - -static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev, "base address not set - upgrade BIOS " - "or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev, "No Via 686A sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - 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, -}; - -static int __init sm_via686a_init(void) -{ - return pci_register_driver(&via686a_pci_driver); -} - -static void __exit sm_via686a_exit(void) -{ - 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 , " - "Mark Studebaker " - "and Bob Dougherty "); -MODULE_DESCRIPTION("VIA 686A Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_via686a_init); -module_exit(sm_via686a_exit); diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c deleted file mode 100644 index 8a40b6976e1..00000000000 --- a/drivers/i2c/chips/w83627ehf.c +++ /dev/null @@ -1,846 +0,0 @@ -/* - w83627ehf - Driver for the hardware monitoring functionality of - the Winbond W83627EHF Super-I/O chip - Copyright (C) 2005 Jean Delvare - - Shamelessly ripped from the w83627hf driver - Copyright (C) 2003 Mark Studebaker - - Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help - in testing and debugging this driver. - - 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. - - - Supports the following chips: - - Chip #vin #fan #pwm #temp chip_id man_id - w83627ehf - 5 - 3 0x88 0x5ca3 - - This is a preliminary version of the driver, only supporting the - fan and temperature inputs. The chip does much more than that. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* Addresses to scan - The actual ISA address is read from Super-I/O configuration space */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(w83627ehf); - -/* - * Super-I/O constants and functions - */ - -static int REG; /* The register to read/write */ -static int VAL; /* The value to read/write */ - -#define W83627EHF_LD_HWM 0x0b - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ - -#define SIO_W83627EHF_ID 0x8840 -#define SIO_ID_MASK 0xFFC0 - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(SIO_REG_LDSEL, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -/* - * ISA constants - */ - -#define REGION_LENGTH 8 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 - -#define W83627EHF_REG_BANK 0x4E -#define W83627EHF_REG_CONFIG 0x40 -#define W83627EHF_REG_CHIP_ID 0x49 -#define W83627EHF_REG_MAN_ID 0x4F - -static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; -static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; - -#define W83627EHF_REG_TEMP1 0x27 -#define W83627EHF_REG_TEMP1_HYST 0x3a -#define W83627EHF_REG_TEMP1_OVER 0x39 -static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; -static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; -static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; -static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; - -/* Fan clock dividers are spread over the following five registers */ -#define W83627EHF_REG_FANDIV1 0x47 -#define W83627EHF_REG_FANDIV2 0x4B -#define W83627EHF_REG_VBAT 0x5D -#define W83627EHF_REG_DIODE 0x59 -#define W83627EHF_REG_SMI_OVT 0x4C - -/* - * Conversions - */ - -static inline unsigned int -fan_from_reg(u8 reg, unsigned int div) -{ - if (reg == 0 || reg == 255) - return 0; - return 1350000U / (reg * div); -} - -static inline unsigned int -div_from_reg(u8 reg) -{ - return 1 << reg; -} - -static inline int -temp1_from_reg(s8 reg) -{ - return reg * 1000; -} - -static inline s8 -temp1_to_reg(int temp) -{ - if (temp <= -128000) - return -128; - if (temp >= 127000) - return 127; - if (temp < 0) - return (temp - 500) / 1000; - return (temp + 500) / 1000; -} - -/* - * Data structures and manipulation thereof - */ - -struct w83627ehf_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - /* Register values */ - u8 fan[5]; - u8 fan_min[5]; - u8 fan_div[5]; - u8 has_fan; /* some fan inputs can be disabled */ - s8 temp1; - s8 temp1_max; - s8 temp1_max_hyst; - s16 temp[2]; - s16 temp_max[2]; - s16 temp_max_hyst[2]; -}; - -static inline int is_word_sized(u16 reg) -{ - return (((reg & 0xff00) == 0x100 - || (reg & 0xff00) == 0x200) - && ((reg & 0x00ff) == 0x50 - || (reg & 0x00ff) == 0x53 - || (reg & 0x00ff) == 0x55)); -} - -/* We assume that the default bank is 0, thus the following two functions do - nothing for registers which live in bank 0. For others, they respectively - set the bank register to the correct value (before the register is - accessed), and back to 0 (afterwards). */ -static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); - } -} - -static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(0, client->addr + DATA_REG_OFFSET); - } -} - -static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - int res, word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - res = inb_p(client->addr + DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); - res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); - } - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - - return res; -} - -static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - int word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, client->addr + DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); - } - outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - return 0; -} - -/* This function assumes that the caller holds data->update_lock */ -static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - u8 reg; - - switch (nr) { - case 0: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) - | ((data->fan_div[0] & 0x03) << 4); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) - | ((data->fan_div[0] & 0x04) << 3); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 1: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) - | ((data->fan_div[1] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) - | ((data->fan_div[1] & 0x04) << 4); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 2: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) - | ((data->fan_div[2] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) - | ((data->fan_div[2] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 3: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) - | (data->fan_div[3] & 0x03); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) - | ((data->fan_div[3] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); - break; - case 4: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) - | ((data->fan_div[4] & 0x03) << 3) - | ((data->fan_div[4] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - break; - } -} - -static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { - /* Fan clock dividers */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); - data->fan_div[2] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - if (data->has_fan & ((1 << 3) | (1 << 4))) { - i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); - data->fan_div[3] = i & 0x03; - data->fan_div[4] = ((i >> 2) & 0x03) - | ((i >> 5) & 0x04); - } - if (data->has_fan & (1 << 3)) { - i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); - data->fan_div[3] |= (i >> 5) & 0x04; - } - - /* Measured fan speeds and limits */ - for (i = 0; i < 5; i++) { - if (!(data->has_fan & (1 << i))) - continue; - - data->fan[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN[i]); - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); - - /* If we failed to measure the fan speed and clock - divider can be increased, let's try that for next - time */ - if (data->fan[i] == 0xff - && data->fan_div[i] < 0x07) { - dev_dbg(&client->dev, "Increasing fan %d " - "clock divider from %u to %u\n", - i, div_from_reg(data->fan_div[i]), - div_from_reg(data->fan_div[i] + 1)); - data->fan_div[i]++; - w83627ehf_write_fan_div(client, i); - /* Preserve min limit if possible */ - if (data->fan_min[i] >= 2 - && data->fan_min[i] != 255) - w83627ehf_write_value(client, - W83627EHF_REG_FAN_MIN[i], - (data->fan_min[i] /= 2)); - } - } - - /* Measured temperatures and limits */ - data->temp1 = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1); - data->temp1_max = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1_OVER); - data->temp1_max_hyst = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1_HYST); - for (i = 0; i < 2; i++) { - data->temp[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP[i]); - data->temp_max[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_OVER[i]); - data->temp_max_hyst[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_HYST[i]); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - return data; -} - -/* - * Sysfs callback functions - */ - -#define show_fan_reg(reg) \ -static ssize_t \ -show_##reg(struct device *dev, char *buf, int nr) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", \ - fan_from_reg(data->reg[nr], \ - div_from_reg(data->fan_div[nr]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -show_fan_div(struct device *dev, char *buf, int nr) -{ - struct w83627ehf_data *data = w83627ehf_update_device(dev); - return sprintf(buf, "%u\n", - div_from_reg(data->fan_div[nr])); -} - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); - unsigned int val = simple_strtoul(buf, NULL, 10); - unsigned int reg; - u8 new_div; - - down(&data->update_lock); - if (!val) { - /* No min limit, alarm disabled */ - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; /* No change */ - dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); - } else if ((reg = 1350000U / val) >= 128 * 255) { - /* Speed below this value cannot possibly be represented, - even with the highest divider (128) */ - data->fan_min[nr] = 254; - new_div = 7; /* 128 == (1 << 7) */ - dev_warn(dev, "fan%u low limit %u below minimum %u, set to " - "minimum\n", nr + 1, val, fan_from_reg(254, 128)); - } else if (!reg) { - /* Speed above this value cannot possibly be represented, - even with the lowest divider (1) */ - data->fan_min[nr] = 1; - new_div = 0; /* 1 == (1 << 0) */ - dev_warn(dev, "fan%u low limit %u above maximum %u, set to " - "maximum\n", nr + 1, val, fan_from_reg(1, 1)); - } else { - /* Automatically pick the best divider, i.e. the one such - that the min limit will correspond to a register value - in the 96..192 range */ - new_div = 0; - while (reg > 192 && new_div < 7) { - reg >>= 1; - new_div++; - } - data->fan_min[nr] = reg; - } - - /* Write both the fan clock divider (if it changed) and the new - fan min (unconditionally) */ - if (new_div != data->fan_div[nr]) { - if (new_div > data->fan_div[nr]) - data->fan[nr] >>= (data->fan_div[nr] - new_div); - else - data->fan[nr] <<= (new_div - data->fan_div[nr]); - - dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", - nr + 1, div_from_reg(data->fan_div[nr]), - div_from_reg(new_div)); - data->fan_div[nr] = new_div; - w83627ehf_write_fan_div(client, nr); - } - w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], - data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t \ -show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan(dev, buf, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_reg_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t \ -show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan_min(dev, buf, offset-1); \ -} \ -static ssize_t \ -store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_reg_fan##offset##_min, \ - store_reg_fan##offset##_min); - -#define sysfs_fan_div_offset(offset) \ -static ssize_t \ -show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_reg_fan##offset##_div, NULL); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_div_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_div_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); -sysfs_fan_div_offset(3); -sysfs_fan_offset(4); -sysfs_fan_min_offset(4); -sysfs_fan_div_offset(4); -sysfs_fan_offset(5); -sysfs_fan_min_offset(5); -sysfs_fan_div_offset(5); - -#define show_temp1_reg(reg) \ -static ssize_t \ -show_##reg(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ -} -show_temp1_reg(temp1); -show_temp1_reg(temp1_max); -show_temp1_reg(temp1_max_hyst); - -#define store_temp1_reg(REG, reg) \ -static ssize_t \ -store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ - u32 val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp1_##reg = temp1_to_reg(val); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ - data->temp1_##reg); \ - up(&data->update_lock); \ - return count; \ -} -store_temp1_reg(OVER, max); -store_temp1_reg(HYST, max_hyst); - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, - show_temp1_max, store_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, - show_temp1_max_hyst, store_temp1_max_hyst); - -#define show_temp_reg(reg) \ -static ssize_t \ -show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", \ - LM75_TEMP_FROM_REG(data->reg[nr])); \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ - u32 val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->reg[nr] = LM75_TEMP_TO_REG(val); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ - data->reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, temp_max); -store_temp_reg(HYST, temp_max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp(dev, buf, offset - 2); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_reg_temp##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t \ -show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_##reg(dev, buf, offset - 2); \ -} \ -static ssize_t \ -store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg(dev, buf, count, offset - 2); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_reg_temp##offset##_##reg, \ - store_reg_temp##offset##_##reg); - -sysfs_temp_offset(2); -sysfs_temp_reg_offset(max, 2); -sysfs_temp_reg_offset(max_hyst, 2); -sysfs_temp_offset(3); -sysfs_temp_reg_offset(max, 3); -sysfs_temp_reg_offset(max_hyst, 3); - -/* - * Driver and client management - */ - -static struct i2c_driver w83627ehf_driver; - -static void w83627ehf_init_client(struct i2c_client *client) -{ - int i; - u8 tmp; - - /* Start monitoring is needed */ - tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); - if (!(tmp & 0x01)) - w83627ehf_write_value(client, W83627EHF_REG_CONFIG, - tmp | 0x01); - - /* Enable temp2 and temp3 if needed */ - for (i = 0; i < 2; i++) { - tmp = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_CONFIG[i]); - if (tmp & 0x01) - w83627ehf_write_value(client, - W83627EHF_REG_TEMP_CONFIG[i], - tmp & 0xfe); - } -} - -static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *client; - struct w83627ehf_data *data; - int i, err = 0; - - if (!i2c_is_isa_adapter(adapter)) - return 0; - - if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { - err = -EBUSY; - goto exit; - } - - if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct w83627ehf_data)); - - client = &data->client; - i2c_set_clientdata(client, data); - client->addr = address; - init_MUTEX(&data->lock); - client->adapter = adapter; - client->driver = &w83627ehf_driver; - client->flags = 0; - - strlcpy(client->name, "w83627ehf", 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(client))) - goto exit_free; - - /* Initialize the chip */ - w83627ehf_init_client(client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 5; i++) - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); - - /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches */ - data->has_fan = 0x07; /* fan1, fan2 and fan3 */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - if (i & (1 << 2)) - data->has_fan |= (1 << 3); - if (i & (1 << 0)) - data->has_fan |= (1 << 4); - - /* Register sysfs hooks */ - device_create_file(&client->dev, &dev_attr_fan1_input); - device_create_file(&client->dev, &dev_attr_fan1_min); - device_create_file(&client->dev, &dev_attr_fan1_div); - device_create_file(&client->dev, &dev_attr_fan2_input); - device_create_file(&client->dev, &dev_attr_fan2_min); - device_create_file(&client->dev, &dev_attr_fan2_div); - device_create_file(&client->dev, &dev_attr_fan3_input); - device_create_file(&client->dev, &dev_attr_fan3_min); - device_create_file(&client->dev, &dev_attr_fan3_div); - - if (data->has_fan & (1 << 3)) { - device_create_file(&client->dev, &dev_attr_fan4_input); - device_create_file(&client->dev, &dev_attr_fan4_min); - device_create_file(&client->dev, &dev_attr_fan4_div); - } - if (data->has_fan & (1 << 4)) { - device_create_file(&client->dev, &dev_attr_fan5_input); - device_create_file(&client->dev, &dev_attr_fan5_min); - device_create_file(&client->dev, &dev_attr_fan5_div); - } - - device_create_file(&client->dev, &dev_attr_temp1_input); - device_create_file(&client->dev, &dev_attr_temp1_max); - device_create_file(&client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&client->dev, &dev_attr_temp2_input); - device_create_file(&client->dev, &dev_attr_temp2_max); - device_create_file(&client->dev, &dev_attr_temp2_max_hyst); - device_create_file(&client->dev, &dev_attr_temp3_input); - device_create_file(&client->dev, &dev_attr_temp3_max); - device_create_file(&client->dev, &dev_attr_temp3_max_hyst); - - return 0; - -exit_free: - kfree(data); -exit_release: - release_region(address, REGION_LENGTH); -exit: - return err; -} - -static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83627ehf_detect); -} - -static int w83627ehf_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; - } - release_region(client->addr, REGION_LENGTH); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static struct i2c_driver w83627ehf_driver = { - .owner = THIS_MODULE, - .name = "w83627ehf", - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627ehf_attach_adapter, - .detach_client = w83627ehf_detach_client, -}; - -static int __init w83627ehf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - superio_enter(); - - val = (superio_inb(SIO_REG_DEVID) << 8) - | superio_inb(SIO_REG_DEVID + 1); - if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627EHF_LD_HWM); - val = (superio_inb(SIO_REG_ADDR) << 8) - | superio_inb(SIO_REG_ADDR + 1); - *address = val & ~(REGION_LENGTH - 1); - if (*address == 0) { - superio_exit(); - return -ENODEV; - } - - /* Activate logical device if needed */ - val = superio_inb(SIO_REG_ENABLE); - if (!(val & 0x01)) - superio_outb(SIO_REG_ENABLE, val | 0x01); - - superio_exit(); - return 0; -} - -static int __init sensors_w83627ehf_init(void) -{ - if (w83627ehf_find(0x2e, &normal_isa[0]) - && w83627ehf_find(0x4e, &normal_isa[0])) - return -ENODEV; - - return i2c_add_driver(&w83627ehf_driver); -} - -static void __exit sensors_w83627ehf_exit(void) -{ - i2c_del_driver(&w83627ehf_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83627EHF driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83627ehf_init); -module_exit(sensors_w83627ehf_exit); diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c deleted file mode 100644 index bd87a42e068..00000000000 --- a/drivers/i2c/chips/w83627hf.c +++ /dev/null @@ -1,1511 +0,0 @@ -/* - w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - Ported to 2.6 by Bernhard C. Schrenk - - 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. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) - w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) - - For other winbond chips, and for i2c support in the above chips, - use w83781d.c. - - Note: automatic ("cruise") fan control for 697, 637 & 627thf not - supported yet. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -static u16 force_addr; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); -static u8 force_i2c = 0x1f; -module_param(force_i2c, byte, 0); -MODULE_PARM_DESC(force_i2c, - "Initialize the i2c address of the sensors"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); - -static int init = 1; -module_param(init, bool, 0); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* modified from kernel/include/traps.c */ -static int REG; /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -static int VAL; /* The value to read/write */ - -/* logical device numbers for superio_select (below) */ -#define W83627HF_LD_FDC 0x00 -#define W83627HF_LD_PRT 0x01 -#define W83627HF_LD_UART1 0x02 -#define W83627HF_LD_UART2 0x03 -#define W83627HF_LD_KBC 0x05 -#define W83627HF_LD_CIR 0x06 /* w83627hf only */ -#define W83627HF_LD_GAME 0x07 -#define W83627HF_LD_MIDI 0x07 -#define W83627HF_LD_GPIO1 0x07 -#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ -#define W83627HF_LD_GPIO2 0x08 -#define W83627HF_LD_GPIO3 0x09 -#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ -#define W83627HF_LD_ACPI 0x0a -#define W83627HF_LD_HWM 0x0b - -#define DEVID 0x20 /* Register: Device ID */ - -#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ -#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ -#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(DEV, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define W627_DEVID 0x52 -#define W627THF_DEVID 0x82 -#define W697_DEVID 0x60 -#define W637_DEVID 0x70 -#define WINB_ACT_REG 0x30 -#define WINB_BASE_REG 0x60 -/* Constants specified below */ - -/* Length of ISA address segment */ -#define WINB_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ - ((nr == 2) ? (0x0150) : \ - (0x27))) -#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ - ((nr == 2) ? (0x153) : \ - (0x3A))) -#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ - ((nr == 2) ? (0x155) : \ - (0x39))) - -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 -#define W83781D_REG_ALARM3 0x450 - -#define W83781D_REG_IRQ 0x4C -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -#define W83781D_REG_VBAT 0x5D - -#define W83627HF_REG_PWM1 0x5A -#define W83627HF_REG_PWM2 0x5B -#define W83627HF_REG_PWMCLK12 0x5C - -#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ -#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ -#define W83627THF_REG_PWM3 0x11 /* 637HF too */ - -#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ - -static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; -static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, - W83627THF_REG_PWM3 }; -#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* Sensor selection */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define TEMP_MIN (-128000) -#define TEMP_MAX ( 127000) - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); - return (u8)(ntemp / 1000); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 1000; -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) - -#define BEEP_MASK_FROM_REG(val) (val) -#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val) -{ - int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* For each registered chip, we need to keep some data in memory. That - data is pointed to by w83627hf_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new client is allocated. */ -struct w83627hf_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_max; /* Register value */ - u8 temp_max_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_max_add[2]; /* Register value */ - u16 temp_max_hyst_add[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beep_mask; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; - u8 vrm_ovt; /* Register value, 627thf & 637hf only */ -}; - - -static int w83627hf_attach_adapter(struct i2c_adapter *adapter); -static int w83627hf_detect(struct i2c_adapter *adapter, int address, - int kind); -static int w83627hf_detach_client(struct i2c_client *client); - -static int w83627hf_read_value(struct i2c_client *client, u16 register); -static int w83627hf_write_value(struct i2c_client *client, u16 register, - u16 value); -static struct w83627hf_data *w83627hf_update_device(struct device *dev); -static void w83627hf_init_client(struct i2c_client *client); - -static struct i2c_driver w83627hf_driver = { - .owner = THIS_MODULE, - .name = "w83627hf", - .id = I2C_DRIVERID_W83627HF, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627hf_attach_adapter, - .detach_client = w83627hf_detach_client, -}; - -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ -} -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define store_in_reg(REG, reg) \ -static ssize_t \ -store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - \ - up(&data->update_lock); \ - return count; \ -} -store_in_reg(MIN, min) -store_in_reg(MAX, max) - -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); - -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset) \ -sysfs_in_reg_offset(min, offset) \ -sysfs_in_reg_offset(max, offset) - -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); - -/* use a different set of functions for in0 */ -static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) -{ - long in0; - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - in0 = (long)((reg * 488 + 70000 + 50) / 100); - else - /* use VRM8 (standard) calculation */ - in0 = (long)IN_FROM_REG(reg); - - return sprintf(buf,"%ld\n", in0); -} - -static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in[0]); -} - -static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in_min[0]); -} - -static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in_max[0]); -} - -static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); - else - /* use VRM8 (standard) calculation */ - data->in_min[0] = IN_TO_REG(val); - - w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); - up(&data->update_lock); - return count; -} - -static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); - else - /* use VRM8 (standard) calculation */ - data->in_max[0] = IN_TO_REG(val); - - w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); -static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, - show_regs_in_min0, store_regs_in_min0); -static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, - show_regs_in_max0, store_regs_in_max0); - -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], \ - (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%ld\n", \ - (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ - } \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg##_add[nr-2]); \ - } else { /* TEMP1 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); - -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset) \ -sysfs_temp_reg_offset(max, offset) \ -sysfs_temp_reg_offset(max_hyst, offset) - -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); - -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) - -static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) - -#define show_beep_reg(REG, reg) \ -static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ -} -show_beep_reg(ENABLE, enable) -show_beep_reg(MASK, mask) - -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ - -static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, val2; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = - w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } - - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); - - up(&data->update_lock); - return count; -} - -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t \ -store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ - show_regs_beep_##reg, store_regs_beep_##reg); - -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); - -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - -static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - data->fan_div[nr] = DIV_TO_REG(val); - - reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) - & (nr==0 ? 0xcf : 0x3f)) - | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); - - reg = (w83627hf_read_value(client, W83781D_REG_VBAT) - & ~(1 << (5 + nr))) - | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83627hf_write_value(client, W83781D_REG_VBAT, reg); - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); - -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); -} - -static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (data->type == w83627thf) { - /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | - (w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); - } else { - data->pwm[nr - 1] = PWM_TO_REG(val); - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - - up(&data->update_lock); - return count; -} - -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwm(3); - -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - -static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); -} - -static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, tmp; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 1: /* PII/Celeron diode */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case 2: /* 3904 */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; - break; - default: - dev_err(&client->dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); - break; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_regs_sensor_##offset, store_regs_sensor_##offset); - -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); - -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - - -/* This function is called when: - * w83627hf_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83627hf_driver is still present) */ -static int w83627hf_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83627hf_detect); -} - -static int w83627hf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - - superio_enter(); - val= superio_inb(DEVID); - if(val != W627_DEVID && - val != W627THF_DEVID && - val != W697_DEVID && - val != W637_DEVID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627HF_LD_HWM); - val = (superio_inb(WINB_BASE_REG) << 8) | - superio_inb(WINB_BASE_REG + 1); - *address = val & ~(WINB_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int w83627hf_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int val; - struct i2c_client *new_client; - struct w83627hf_data *data; - int err = 0; - const char *client_name = ""; - - if (!i2c_is_isa_adapter(adapter)) { - err = -ENODEV; - goto ERROR0; - } - - if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); - - if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { - err = -EBUSY; - goto ERROR0; - } - - if(force_addr) { - printk("w83627hf.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(W83627HF_LD_HWM); - superio_outb(WINB_BASE_REG, address >> 8); - superio_outb(WINB_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - val= superio_inb(DEVID); - if(val == W627_DEVID) - kind = w83627hf; - else if(val == W697_DEVID) - kind = w83697hf; - else if(val == W627THF_DEVID) - kind = w83627thf; - else if(val == W637_DEVID) - kind = w83637hf; - else { - dev_info(&adapter->dev, - "Unsupported chip (dev_id=0x%02X).\n", val); - goto ERROR1; - } - - superio_select(W83627HF_LD_HWM); - if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) - superio_outb(WINB_ACT_REG, 1); - superio_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 w83627hf_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct w83627hf_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &w83627hf_driver; - new_client->flags = 0; - - - if (kind == w83627hf) { - client_name = "w83627hf"; - } else if (kind == w83627thf) { - client_name = "w83627thf"; - } else if (kind == w83697hf) { - client_name = "w83697hf"; - } else if (kind == w83637hf) { - client_name = "w83637hf"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - 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 ERROR2; - - data->lm75 = NULL; - - /* Initialize the chip */ - w83627hf_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); - data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); - data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - if (kind != w83697hf) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - if (kind != w83627thf && kind != w83637hf) { - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - } - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - if (kind != w83697hf) - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83697hf) - device_create_file_temp(new_client, 3); - - if (kind != w83697hf) - device_create_file_vid(new_client); - - if (kind != w83697hf) - device_create_file_vrm(new_client); - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - if (kind != w83697hf) - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - if (kind == w83627thf || kind == w83637hf) - device_create_file_pwm(new_client, 3); - - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83697hf) - device_create_file_sensor(new_client, 3); - - return 0; - - ERROR2: - kfree(data); - ERROR1: - release_region(address, WINB_EXTENT); - ERROR0: - return err; -} - -static int w83627hf_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; - } - - release_region(client->addr, WINB_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - - -/* - ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83627hf_read_value(struct i2c_client *client, u16 reg) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int res, word_sized; - - down(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&data->lock); - return res; -} - -static int w83627thf_read_gpio5(struct i2c_client *client) -{ - int res = 0xff, sel; - - superio_enter(); - superio_select(W83627HF_LD_GPIO5); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { - dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); - goto exit; - } - - /* Make sure the pins are configured for input - There must be at least five (VRM 9), and possibly 6 (VRM 10) */ - sel = superio_inb(W83627THF_GPIO5_IOSR); - if ((sel & 0x1f) != 0x1f) { - dev_dbg(&client->dev, "GPIO5 not configured for VID " - "function\n"); - goto exit; - } - - dev_info(&client->dev, "Reading VID from GPIO5\n"); - res = superio_inb(W83627THF_GPIO5_DR) & sel; - -exit: - superio_exit(); - return res; -} - -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int word_sized; - - down(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&data->lock); - return 0; -} - -/* Called when we have found a new W83781D. It should set limits, etc. */ -static void w83627hf_init_client(struct i2c_client *client) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int i; - int type = data->type; - u8 tmp; - - if(init) { - /* save this register */ - i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the register and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - /* Disable master beep-enable (reset turns it on). - Individual beeps should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - /* Minimize conflicts with other winbond i2c-only clients... */ - /* disable i2c subclients... how to disable main i2c client?? */ - /* force i2c address to relatively uncommon address */ - w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); - - /* Read VID only once */ - if (w83627hf == data->type || w83637hf == data->type) { - int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); - data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (w83627thf == data->type) { - data->vid = w83627thf_read_gpio5(client) & 0x3f; - } - - /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type) { - data->vrm_ovt = - w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); - data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; - } else { - /* Convert VID to voltage based on default VRM */ - data->vrm = i2c_which_vrm(); - } - - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83627hf_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if ((type == w83697hf) && (i == 2)) - break; - } - - if(init) { - /* Enable temp2 */ - tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " - "might not make sense\n"); - w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83697hf) { - tmp = w83627hf_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " - "readings might not make sense\n"); - w83627hf_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - - if (type == w83627hf) { - /* enable PWM2 control (can't hurt since PWM reg - should have been reset to 0xff) */ - w83627hf_write_value(client, W83627HF_REG_PWMCLK12, - 0x19); - } - /* enable comparator mode for temp2 and temp3 so - alarm indication will work correctly */ - i = w83627hf_read_value(client, W83781D_REG_IRQ); - if (!(i & 0x40)) - w83627hf_write_value(client, W83781D_REG_IRQ, - i | 0x40); - } - - /* Start monitoring */ - w83627hf_write_value(client, W83781D_REG_CONFIG, - (w83627hf_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static struct w83627hf_data *w83627hf_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 8; i++) { - /* skip missing sensors */ - if (((data->type == w83697hf) && (i == 1)) || - ((data->type == w83627thf || data->type == w83637hf) - && (i == 4 || i == 5))) - continue; - data->in[i] = - w83627hf_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83627hf_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83627hf_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - u8 tmp = w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, i)); - /* bits 0-3 are reserved in 627THF */ - if (data->type == w83627thf) - tmp &= 0xf0; - data->pwm[i - 1] = tmp; - if(i == 2 && - (data->type == w83627hf || data->type == w83697hf)) - break; - } - - data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); - data->temp_max = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); - data->temp_max_hyst = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); - data->temp_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP(2)); - data->temp_max_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); - data->temp_max_hyst_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83697hf) { - data->temp_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP(3)); - data->temp_max_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); - data->temp_max_hyst_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); - } - - i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; - data->alarms = - w83627hf_read_value(client, W83781D_REG_ALARM1) | - (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beep_mask = ((i & 0x7f) << 8) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_w83627hf_init(void) -{ - int addr; - - if (w83627hf_find(0x2e, &addr) - && w83627hf_find(0x4e, &addr)) { - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&w83627hf_driver); -} - -static void __exit sensors_w83627hf_exit(void) -{ - i2c_del_driver(&w83627hf_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83627HF driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83627hf_init); -module_exit(sensors_w83627hf_exit); diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c deleted file mode 100644 index 0bb131ce09e..00000000000 --- a/drivers/i2c/chips/w83781d.c +++ /dev/null @@ -1,1632 +0,0 @@ -/* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - 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. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 0 3 0x31 0x12c3 yes no - as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no - w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes - w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* 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 int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); -I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init = 1; -module_param(init, bool, 0); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* Constants specified below */ - -/* Length of ISA address segment */ -#define W83781D_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_BANK 0x4E -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ - ((nr == 2) ? (0x0150) : \ - (0x27))) -#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ - ((nr == 2) ? (0x153) : \ - (0x3A))) -#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ - ((nr == 2) ? (0x155) : \ - (0x39))) - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 -#define W83781D_REG_ALARM3 0x450 /* not on W83781D */ - -#define W83781D_REG_IRQ 0x4C -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -/* 782D/783S only */ -#define W83781D_REG_VBAT 0x5D - -/* PWM 782D (1-4) and 783S (1-2) only */ -#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ - /* on which is which; */ -#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ - /* However 782d is probably wrong. */ -#define W83781D_REG_PWM3 0x5E -#define W83781D_REG_PWM4 0x5F -#define W83781D_REG_PWMCLK12 0x5C -#define W83781D_REG_PWMCLK34 0x45C -static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, - W83781D_REG_PWM3, W83781D_REG_PWM4 -}; - -#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* The following are undocumented in the data sheets however we - received the information in an email from Winbond tech support */ -/* Sensor selection - not on 781d */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; - -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; - -#define W83781D_DEFAULT_BETA 3435 - -/* RT Table registers */ -#define W83781D_REG_RT_IDX 0x50 -#define W83781D_REG_RT_VAL 0x51 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16) / 10) - -static inline u8 -FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) - -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ - (val) ^ 0x7fff : (val)) -#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ - (~(val)) & 0x7fff : (val) & 0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) -#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 -DIV_TO_REG(long val, enum chips type) -{ - int i; - val = SENSORS_LIMIT(val, 1, - ((type == w83781d - || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* There are some complications in a module like this. First off, W83781D chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - W83781D chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the W83781D at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. That - data is pointed to by w83781d_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ -struct w83781d_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75[2]; /* for secondary I2C addresses */ - /* array of 2 pointers to subclients */ - - u8 in[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_max; /* Register value */ - u8 temp_max_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_max_add[2]; /* Register value */ - u16 temp_max_hyst_add[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beep_mask; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[4]; /* Register value */ - u8 pwmenable[4]; /* Boolean */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; -}; - -static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); -static int w83781d_detach_client(struct i2c_client *client); - -static int w83781d_read_value(struct i2c_client *client, u16 register); -static int w83781d_write_value(struct i2c_client *client, u16 register, - u16 value); -static struct w83781d_data *w83781d_update_device(struct device *dev); -static void w83781d_init_client(struct i2c_client *client); - -static struct i2c_driver w83781d_driver = { - .owner = THIS_MODULE, - .name = "w83781d", - .id = I2C_DRIVERID_W83781D, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83781d_attach_adapter, - .detach_client = w83781d_detach_client, -}; - -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \ -} -show_in_reg(in); -show_in_reg(in_min); -show_in_reg(in_max); - -#define store_in_reg(REG, reg) \ -static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10) / 10; \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ - \ - up(&data->update_lock); \ - return count; \ -} -store_in_reg(MIN, min); -store_in_reg(MAX, max); - -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); - -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset); \ -sysfs_in_reg_offset(min, offset); \ -sysfs_in_reg_offset(max, offset); - -sysfs_in_offsets(0); -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); - -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - 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)); \ - } \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ - s32 val; \ - \ - val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - 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 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); - -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset); \ -sysfs_temp_reg_offset(max, offset); \ -sysfs_temp_reg_offset(max_hyst, offset); - -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); - -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} - -static -DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid); -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} - -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} - -static -DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); -static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static -DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms); -static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type)); -} -static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_ENABLE_FROM_REG(data->beep_enable)); -} - -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ - -static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, val2; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val, data->type); - w83781d_write_value(client, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - - if ((data->type != w83781d) && (data->type != as99127f)) { - w83781d_write_value(client, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - } - - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } - - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); - - up(&data->update_lock); - return count; -} - -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); - -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); - -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - -static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - data->fan_div[nr] = DIV_TO_REG(val, data->type); - - reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) - & (nr==0 ? 0xcf : 0x3f)) - | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = (w83781d_read_value(client, W83781D_REG_VBAT) - & ~(1 << (5 + nr))) - | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); - -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); -} - -static ssize_t -show_pwmenable_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); -} - -static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm[nr - 1] = PWM_TO_REG(val); - w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t -store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, reg; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 0: - case 1: - reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); - w83781d_write_value(client, W83781D_REG_PWMCLK12, - (reg & 0xf7) | (val << 3)); - - reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, - (reg & 0xef) | (!val << 4)); - - data->pwmenable[nr - 1] = val; - break; - - default: - up(&data->update_lock); - return -EINVAL; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -#define sysfs_pwmenable(offset) \ -static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwmenable_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwmenable_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ -sysfs_pwm(3); -sysfs_pwm(4); - -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - -#define device_create_file_pwmenable(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \ -} while (0) - -static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); -} - -static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, tmp; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 1: /* PII/Celeron diode */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case 2: /* 3904 */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; - break; - default: - dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); - break; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); - -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); - -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - -/* This function is called when: - * w83781d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83781d_driver is still present) */ -static int -w83781d_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83781d_detect); -} - -/* Assumes that adapter is of I2C, not ISA variety. - * OTHERWISE DON'T CALL THIS - */ -static int -w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, - struct i2c_client *new_client) -{ - int i, val1 = 0, id; - int err; - const char *client_name = ""; - struct w83781d_data *data = i2c_get_clientdata(new_client); - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, "Invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -EINVAL; - goto ERROR_SC_1; - } - } - w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << 4)); - data->lm75[0]->addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val1 & 0x07); - } - - if (kind != w83783s) { - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); - - if (force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1]->addr = force_subclients[3]; - } else { - data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); - } - if (data->lm75[0]->addr == data->lm75[1]->addr) { - dev_err(&new_client->dev, - "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0]->addr); - err = -EBUSY; - goto ERROR_SC_2; - } - } - - if (kind == w83781d) - client_name = "w83781d subclient"; - else if (kind == w83782d) - client_name = "w83782d subclient"; - else if (kind == w83783s) - client_name = "w83783s subclient"; - else if (kind == w83627hf) - client_name = "w83627hf subclient"; - else if (kind == as99127f) - client_name = "as99127f subclient"; - - for (i = 0; i <= 1; i++) { - /* store all data in w83781d */ - i2c_set_clientdata(data->lm75[i], NULL); - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &w83781d_driver; - data->lm75[i]->flags = 0; - strlcpy(data->lm75[i]->name, client_name, - I2C_NAME_SIZE); - if ((err = i2c_attach_client(data->lm75[i]))) { - dev_err(&new_client->dev, "Subclient %d " - "registration at address 0x%x " - "failed.\n", i, data->lm75[i]->addr); - if (i == 1) - goto ERROR_SC_3; - goto ERROR_SC_2; - } - if (kind == w83783s) - break; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - if (NULL != data->lm75[1]) - kfree(data->lm75[1]); -ERROR_SC_1: - if (NULL != data->lm75[0]) - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int -w83781d_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i = 0, val1 = 0, val2; - struct i2c_client *new_client; - struct w83781d_data *data; - int err; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - enum vendor { winbond, asus } vendid; - - if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - err = -EINVAL; - goto ERROR0; - } - - /* Prevent users from forcing a kind for a bus it isn't supposed - to possibly be on */ - if (is_isa && (kind == as99127f || kind == w83783s)) { - dev_err(&adapter->dev, - "Cannot force I2C-only chip for ISA address 0x%02x.\n", - address); - err = -EINVAL; - goto ERROR0; - } - - if (is_isa) - if (!request_region(address, W83781D_EXTENT, - w83781d_driver.name)) { - dev_dbg(&adapter->dev, "Request of region " - "0x%x-0x%x for w83781d failed\n", address, - address + W83781D_EXTENT - 1); - err = -EBUSY; - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 1\n"); - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - val2 = inb_p(address + 5) & 0x7f; - if (val2 != (~i & 0x7f)) { - outb_p(i, address + 5); - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 2 (0x%x != " - "0x%x at 0x%x)\n", val2, ~i & 0x7f, - address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* 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 w83781d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct w83781d_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &w83781d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The w8378?d may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the Winbond will be reset to the right - bank. */ - if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) { - dev_dbg(&new_client->dev, "Detection failed at step " - "3\n"); - err = -ENODEV; - goto ERROR2; - } - val1 = w83781d_read_value(new_client, W83781D_REG_BANK); - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - /* Check for Winbond or Asus ID if in bank 0 */ - if ((!(val1 & 0x07)) && - (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) - || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { - dev_dbg(&new_client->dev, "Detection failed at step " - "4\n"); - err = -ENODEV; - goto ERROR2; - } - /* If Winbond SMBus, check address at 0x48. - Asus doesn't support, except for as99127f rev.2 */ - if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || - ((val1 & 0x80) && (val2 == 0x5c)))) { - if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) { - dev_dbg(&new_client->dev, "Detection failed " - "at step 5\n"); - err = -ENODEV; - goto ERROR2; - } - } - } - - /* We have either had a force parameter, or we have already detected the - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(new_client, W83781D_REG_BANK, - (w83781d_read_value(new_client, - W83781D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - if (val2 == 0x5c) - vendid = winbond; - else if (val2 == 0x12) - vendid = asus; - else { - dev_dbg(&new_client->dev, "Chip was made by neither " - "Winbond nor Asus?\n"); - err = -ENODEV; - goto ERROR2; - } - - val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); - if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) - kind = w83781d; - else if (val1 == 0x30 && vendid == winbond) - kind = w83782d; - else if (val1 == 0x40 && vendid == winbond && !is_isa - && address == 0x2d) - kind = w83783s; - else if (val1 == 0x21 && vendid == winbond) - kind = w83627hf; - else if (val1 == 0x31 && !is_isa && address >= 0x28) - kind = as99127f; - else { - if (kind == 0) - dev_warn(&new_client->dev, "Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -EINVAL; - goto ERROR2; - } - } - - if (kind == w83781d) { - client_name = "w83781d"; - } else if (kind == w83782d) { - client_name = "w83782d"; - } else if (kind == w83783s) { - client_name = "w83783s"; - } else if (kind == w83627hf) { - client_name = "w83627hf"; - } else if (kind == as99127f) { - client_name = "as99127f"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - - 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 ERROR2; - - /* attach secondary i2c lm75-like clients */ - if (!is_isa) { - if ((err = w83781d_detect_subclients(adapter, address, - kind, new_client))) - goto ERROR3; - } else { - data->lm75[0] = NULL; - data->lm75[1] = NULL; - } - - /* Initialize the chip */ - w83781d_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 1; i <= 3; i++) { - data->fan_min[i - 1] = w83781d_read_value(new_client, - W83781D_REG_FAN_MIN(i)); - } - if (kind != w83781d && kind != as99127f) - for (i = 0; i < 4; i++) - data->pwmenable[i] = 1; - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - if (kind != w83783s) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - if (kind != as99127f && kind != w83781d && kind != w83783s) { - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - } - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83783s) - device_create_file_temp(new_client, 3); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - if (kind != w83781d && kind != as99127f) { - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - device_create_file_pwmenable(new_client, 2); - } - if (kind == w83782d && !is_isa) { - device_create_file_pwm(new_client, 3); - device_create_file_pwm(new_client, 4); - } - - if (kind != as99127f && kind != w83781d) { - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83783s) - device_create_file_sensor(new_client, 3); - } - - return 0; - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, W83781D_EXTENT); -ERROR0: - return err; -} - -static int -w83781d_detach_client(struct i2c_client *client) -{ - int err; - - if (i2c_is_isa_client(client)) - release_region(client->addr, W83781D_EXTENT); - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if (i2c_get_clientdata(client)==NULL) { - /* subclients */ - kfree(client); - } else { - /* main client */ - kfree(i2c_get_clientdata(client)); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int -w83781d_read_value(struct i2c_client *client, u16 reg) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int res, word_sized, bank; - struct i2c_client *cl; - - down(&data->lock); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); - break; - case 0x55: /* OVER */ - default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); - } - up(&data->lock); - return res; -} - -static int -w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int word_sized, bank; - struct i2c_client *cl; - - down(&data->lock); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, - value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); - } - up(&data->lock); - return 0; -} - -/* Called when we have found a new W83781D. It should set limits, etc. */ -static void -w83781d_init_client(struct i2c_client *client) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int i, p; - int type = data->type; - u8 tmp; - - if (init && type != as99127f) { /* this resets registers we don't have - documentation for on the as99127f */ - /* save these registers */ - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - p = w83781d_read_value(client, W83781D_REG_PWMCLK12); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the registers and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - w83781d_write_value(client, W83781D_REG_PWMCLK12, p); - /* Disable master beep-enable (reset turns it on). - Individual beep_mask should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - data->vrm = i2c_which_vrm(); - - if ((type != w83781d) && (type != as99127f)) { - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83781d_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if (type == w83783s && i == 2) - break; - } - } - - if (init && type != as99127f) { - /* Enable temp2 */ - tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " - "might not make sense\n"); - w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83783s) { - tmp = w83781d_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " - "readings might not make sense\n"); - w83781d_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - - if (type != w83781d) { - /* enable comparator mode for temp2 and temp3 so - alarm indication will work correctly */ - i = w83781d_read_value(client, W83781D_REG_IRQ); - if (!(i & 0x40)) - w83781d_write_value(client, W83781D_REG_IRQ, - i | 0x40); - } - } - - /* Start monitoring */ - w83781d_write_value(client, W83781D_REG_CONFIG, - (w83781d_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static struct w83781d_data *w83781d_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(dev, "Starting device update\n"); - - for (i = 0; i <= 8; i++) { - if (data->type == w83783s && i == 1) - continue; /* 783S has no in1 */ - data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) - && (data->type != w83627hf) && (i == 6)) - break; - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); - } - if (data->type != w83781d && data->type != as99127f) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(i)); - if ((data->type != w83782d - || i2c_is_isa_client(client)) - && i == 2) - break; - } - /* Only PWM2 can be disabled */ - data->pwmenable[1] = (w83781d_read_value(client, - W83781D_REG_PWMCLK12) & 0x08) >> 3; - } - - data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); - data->temp_max = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); - data->temp_max_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); - data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP(2)); - data->temp_max_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); - data->temp_max_hyst_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83783s) { - data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP(3)); - data->temp_max_add[1] = - w83781d_read_value(client, - W83781D_REG_TEMP_OVER(3)); - data->temp_max_hyst_add[1] = - w83781d_read_value(client, - W83781D_REG_TEMP_HYST(3)); - } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client, - W83781D_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - } - data->alarms = - w83781d_read_value(client, - W83781D_REG_ALARM1) + - (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); - if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms |= - w83781d_read_value(client, - W83781D_REG_ALARM3) << 16; - } - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beep_mask = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); - if ((data->type != w83781d) && (data->type != as99127f)) { - data->beep_mask |= - w83781d_read_value(client, - W83781D_REG_BEEP_INTS3) << 16; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init -sensors_w83781d_init(void) -{ - return i2c_add_driver(&w83781d_driver); -} - -static void __exit -sensors_w83781d_exit(void) -{ - i2c_del_driver(&w83781d_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83781D driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83781d_init); -module_exit(sensors_w83781d_exit); diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c deleted file mode 100644 index 4469d52aba4..00000000000 --- a/drivers/i2c/chips/w83l785ts.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Jean Delvare - * - * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made - * by Winbond. It reports a single external temperature with a 1 deg - * resolution and a 3 deg accuracy. Datasheet can be obtained from - * Winbond's website at: - * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - * - * Ported to Linux 2.6 by Wolfgang Ziegler and Jean Delvare - * . - * - * Thanks to James Bolt for benchmarking the read - * error handling mechanism. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* How many retries on register read error */ -#define MAX_RETRIES 5 - -/* - * Address to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(w83l785ts); - -/* - * The W83L785TS-S registers - * Manufacturer ID is 0x5CA3 for Winbond. - */ - -#define W83L785TS_REG_MAN_ID1 0x4D -#define W83L785TS_REG_MAN_ID2 0x4C -#define W83L785TS_REG_CHIP_ID 0x4E -#define W83L785TS_REG_CONFIG 0x40 -#define W83L785TS_REG_TYPE 0x52 -#define W83L785TS_REG_TEMP 0x27 -#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ - -/* - * Conversions - * The W83L785TS-S uses signed 8-bit values. - */ - -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) - -/* - * Functions declaration - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, - int kind); -static int w83l785ts_detach_client(struct i2c_client *client); -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); -static struct w83l785ts_data *w83l785ts_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver w83l785ts_driver = { - .owner = THIS_MODULE, - .name = "w83l785ts", - .id = I2C_DRIVERID_W83L785TS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83l785ts_attach_adapter, - .detach_client = w83l785ts_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct w83l785ts_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 temp, temp_over; -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); - -/* - * Real code - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83l785ts_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct w83l785ts_data *data; - int err = 0; - - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct w83l785ts_data)); - - - /* The common I2C client data is placed right before the - * W83L785TS-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &w83l785ts_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, W83L785TS-S). A zero kind means - * that the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - if (kind < 0) { /* detection */ - if (((w83l785ts_read_value(new_client, - W83L785TS_REG_CONFIG, 0) & 0x80) != 0x00) - || ((w83l785ts_read_value(new_client, - W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) { - dev_dbg(&adapter->dev, - "W83L785TS-S detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u16 man_id; - u8 chip_id; - - man_id = (w83l785ts_read_value(new_client, - W83L785TS_REG_MAN_ID1, 0) << 8) + - w83l785ts_read_value(new_client, - W83L785TS_REG_MAN_ID2, 0); - chip_id = w83l785ts_read_value(new_client, - W83L785TS_REG_CHIP_ID, 0); - - if (man_id == 0x5CA3) { /* Winbond */ - if (chip_id == 0x70) { /* W83L785TS-S */ - kind = w83l785ts; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%04X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - /* We can fill in the remaining client fields. */ - strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Default values in case the first read fails (unlikely). */ - data->temp_over = data->temp = 0; - - /* Tell the I2C layer a new client has arrived. */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* - * Initialize the W83L785TS chip - * Nothing yet, assume it is already started. - */ - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int w83l785ts_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 u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) -{ - int value, i; - - /* Frequent read errors have been reported on Asus boards, so we - * retry on read errors. If it still fails (unlikely), return the - * default value requested by the caller. */ - for (i = 1; i <= MAX_RETRIES; i++) { - value = i2c_smbus_read_byte_data(client, reg); - if (value >= 0) { - dev_dbg(&client->dev, "Read 0x%02x from register " - "0x%02x.\n", value, reg); - return value; - } - dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i); - msleep(i); - } - - dev_err(&client->dev, "Couldn't read value from register 0x%02x. " - "Please report.\n", reg); - return defval; -} - -static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83l785ts_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { - dev_dbg(&client->dev, "Updating w83l785ts data.\n"); - data->temp = w83l785ts_read_value(client, - W83L785TS_REG_TEMP, data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_w83l785ts_init(void) -{ - return i2c_add_driver(&w83l785ts_driver); -} - -static void __exit sensors_w83l785ts_exit(void) -{ - i2c_del_driver(&w83l785ts_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83L785TS-S driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83l785ts_init); -module_exit(sensors_w83l785ts_exit); -- cgit v1.2.3 From 45b1b196677b8009ab6cdc4b656265f1d7015c1b Mon Sep 17 00:00:00 2001 From: Keiichiro Tokunaga Date: Wed, 2 Mar 2005 00:00:00 -0500 Subject: [ACPI] update CONFIG_ACPI_CONTAINER Kconfig help Signed-off-by: Keiichiro Tokunaga Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 670fdb5142d..4aa26acbc46 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -327,8 +327,13 @@ config ACPI_CONTAINER depends on EXPERIMENTAL default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO) ---help--- - This is the ACPI generic container driver which supports - ACPI0004, PNP0A05 and PNP0A06 devices + This allows _physical_ insertion and removal of CPUs and memory. + This can be useful, for example, on NUMA machines that support + ACPI based physical hotplug of nodes, or non-NUMA machines that + support physical cpu/memory hot-plug. + + If one selects "m", this driver can be loaded with + "modprobe acpi_container". config ACPI_HOTPLUG_MEMORY tristate "Memory Hotplug" -- cgit v1.2.3 From bd4698dad3023ae137b366c736e29ca6eaf3b9f7 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 18 Mar 2005 15:35:22 -0500 Subject: [ACPI] Allow simultaneous Fixed Feature and Control Method buttons delete /proc/acpi/button http://bugzilla.kernel.org/show_bug.cgi?id=1920 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/button.c | 245 +------------------------------------------------- 1 file changed, 1 insertion(+), 244 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ec4430e3053..0f45d45f05a 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -26,9 +26,6 @@ #include #include #include -#include -#include -#include #include #include @@ -36,9 +33,6 @@ #define ACPI_BUTTON_COMPONENT 0x00080000 #define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" #define ACPI_BUTTON_CLASS "button" -#define ACPI_BUTTON_FILE_INFO "info" -#define ACPI_BUTTON_FILE_STATE "state" -#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 #define ACPI_BUTTON_NOTIFY_STATUS 0x80 #define ACPI_BUTTON_SUBCLASS_POWER "power" @@ -70,8 +64,6 @@ MODULE_LICENSE("GPL"); static int acpi_button_add (struct acpi_device *device); static int acpi_button_remove (struct acpi_device *device, int type); -static int acpi_button_info_open_fs(struct inode *inode, struct file *file); -static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { .name = ACPI_BUTTON_DRIVER_NAME, @@ -90,187 +82,6 @@ struct acpi_button { unsigned long pushed; }; -static struct file_operations acpi_button_info_fops = { - .open = acpi_button_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct file_operations acpi_button_state_fops = { - .open = acpi_button_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -/* -------------------------------------------------------------------------- - FS Interface (/proc) - -------------------------------------------------------------------------- */ - -static struct proc_dir_entry *acpi_button_dir; - -static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_button *button = (struct acpi_button *) seq->private; - - ACPI_FUNCTION_TRACE("acpi_button_info_seq_show"); - - if (!button || !button->device) - return_VALUE(0); - - seq_printf(seq, "type: %s\n", - acpi_device_name(button->device)); - - return_VALUE(0); -} - -static int acpi_button_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_info_seq_show, PDE(inode)->data); -} - -static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_button *button = (struct acpi_button *) seq->private; - acpi_status status; - unsigned long state; - - ACPI_FUNCTION_TRACE("acpi_button_state_seq_show"); - - if (!button || !button->device) - return_VALUE(0); - - status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state); - if (ACPI_FAILURE(status)) { - seq_printf(seq, "state: unsupported\n"); - } - else{ - seq_printf(seq, "state: %s\n", (state ? "open" : "closed")); - } - - return_VALUE(0); -} - -static int acpi_button_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); -} - -static int -acpi_button_add_fs ( - struct acpi_device *device) -{ - struct proc_dir_entry *entry = NULL; - struct acpi_button *button = NULL; - - ACPI_FUNCTION_TRACE("acpi_button_add_fs"); - - if (!device || !acpi_driver_data(device)) - return_VALUE(-EINVAL); - - button = acpi_driver_data(device); - - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_LID: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, - acpi_button_dir); - break; - } - - if (!entry) - return_VALUE(-ENODEV); - entry->owner = THIS_MODULE; - - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); - if (!acpi_device_dir(device)) - return_VALUE(-ENODEV); - acpi_device_dir(device)->owner = THIS_MODULE; - - /* 'info' [R] */ - entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_BUTTON_FILE_INFO)); - else { - entry->proc_fops = &acpi_button_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - - /* show lid state [R] */ - if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_BUTTON_FILE_INFO)); - else { - entry->proc_fops = &acpi_button_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - } - - return_VALUE(0); -} - - -static int -acpi_button_remove_fs ( - struct acpi_device *device) -{ - struct acpi_button *button = NULL; - - ACPI_FUNCTION_TRACE("acpi_button_remove_fs"); - - button = acpi_driver_data(device); - if (acpi_device_dir(device)) { - if (button->type == ACPI_BUTTON_TYPE_LID) - remove_proc_entry(ACPI_BUTTON_FILE_STATE, - acpi_device_dir(device)); - remove_proc_entry(ACPI_BUTTON_FILE_INFO, - acpi_device_dir(device)); - - remove_proc_entry(acpi_device_bid(device), - acpi_device_dir(device)->parent); - - - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_LID: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, - acpi_button_dir); - break; - } - acpi_device_dir(device) = NULL; - } - - return_VALUE(0); -} - - /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -310,8 +121,7 @@ acpi_button_notify_fixed ( ACPI_FUNCTION_TRACE("acpi_button_notify_fixed"); - if (!button) - return_ACPI_STATUS(AE_BAD_PARAMETER); + BUG_ON(!button); acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button); @@ -327,10 +137,6 @@ acpi_button_add ( acpi_status status = AE_OK; struct acpi_button *button = NULL; - static struct acpi_device *power_button; - static struct acpi_device *sleep_button; - static struct acpi_device *lid_button; - ACPI_FUNCTION_TRACE("acpi_button_add"); if (!device) @@ -391,42 +197,6 @@ acpi_button_add ( goto end; } - /* - * Ensure only one button of each type is used. - */ - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - if (!power_button) - power_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - if (!sleep_button) - sleep_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - case ACPI_BUTTON_TYPE_LID: - if (!lid_button) - lid_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - } - - result = acpi_button_add_fs(device); - if (result) - goto end; - switch (button->type) { case ACPI_BUTTON_TYPE_POWERF: status = acpi_install_fixed_event_handler ( @@ -470,7 +240,6 @@ acpi_button_add ( end: if (result) { - acpi_button_remove_fs(device); kfree(button); } @@ -511,8 +280,6 @@ acpi_button_remove (struct acpi_device *device, int type) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error removing notify handler\n")); - acpi_button_remove_fs(device); - kfree(button); return_VALUE(0); @@ -526,21 +293,14 @@ acpi_button_init (void) ACPI_FUNCTION_TRACE("acpi_button_init"); - acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); - if (!acpi_button_dir) - return_VALUE(-ENODEV); - acpi_button_dir->owner = THIS_MODULE; - result = acpi_bus_register_driver(&acpi_button_driver); if (result < 0) { - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); return_VALUE(-ENODEV); } return_VALUE(0); } - static void __exit acpi_button_exit (void) { @@ -548,11 +308,8 @@ acpi_button_exit (void) acpi_bus_unregister_driver(&acpi_button_driver); - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); - return_VOID; } - module_init(acpi_button_init); module_exit(acpi_button_exit); -- cgit v1.2.3 From be91492ca871e58f61b517cfba541095bb60001c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 18 Mar 2005 16:00:29 -0500 Subject: [ACPI] CONFIG_ACPI now depends on CONFIG_PM Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4aa26acbc46..ceecc5634e7 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,7 @@ # menu "ACPI (Advanced Configuration and Power Interface) Support" + depends on PM depends on !X86_VISWS depends on !IA64_HP_SIM depends on IA64 || X86 @@ -56,7 +57,7 @@ if ACPI_INTERPRETER config ACPI_SLEEP bool "Sleep States (EXPERIMENTAL)" depends on X86 - depends on EXPERIMENTAL && PM + depends on EXPERIMENTAL default y ---help--- This option adds support for ACPI suspend states. -- cgit v1.2.3 From e2a5b420f716cd1a46674b1a90389612eced916f Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 18 Mar 2005 16:20:46 -0500 Subject: [ACPI] ACPI poweroff fix Register an "acpi" system device to be notified of shutdown preparation. This depends on CONFIG_PM http://bugzilla.kernel.org/show_bug.cgi?id=4041 Signed-off-by: Alexey Starikovskiy Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/sleep/main.c | 74 +++++++++++++++++---------------------- drivers/acpi/sleep/poweroff.c | 81 ++++++++++++++++++++++++++++++++++++++----- drivers/base/sys.c | 1 - 3 files changed, 105 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 0a5d2a94131..7249ba2b7a2 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -1,6 +1,7 @@ /* * sleep.c - ACPI sleep support. * + * Copyright (c) 2005 Alexey Starikovskiy * Copyright (c) 2004 David Shaohua Li * Copyright (c) 2000-2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Lab @@ -14,7 +15,6 @@ #include #include #include -#include #include #include #include "sleep.h" @@ -27,10 +27,11 @@ extern void do_suspend_lowlevel_s4bios(void); extern void do_suspend_lowlevel(void); static u32 acpi_suspend_states[] = { - [PM_SUSPEND_ON] = ACPI_STATE_S0, - [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, - [PM_SUSPEND_MEM] = ACPI_STATE_S3, - [PM_SUSPEND_DISK] = ACPI_STATE_S4, + [PM_SUSPEND_ON] = ACPI_STATE_S0, + [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, + [PM_SUSPEND_MEM] = ACPI_STATE_S3, + [PM_SUSPEND_DISK] = ACPI_STATE_S4, + [PM_SUSPEND_MAX] = ACPI_STATE_S5 }; static int init_8259A_after_S1; @@ -44,30 +45,20 @@ static int init_8259A_after_S1; * wakeup code to the waking vector. */ +extern int acpi_sleep_prepare(u32 acpi_state); +extern void acpi_power_off(void); + static int acpi_pm_prepare(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; - if (!sleep_states[acpi_state]) + if (!sleep_states[acpi_state]) { + printk("acpi_pm_prepare does not support %d \n", pm_state); return -EPERM; - - /* do we have a wakeup address for S2 and S3? */ - /* Here, we support only S4BIOS, those we set the wakeup address */ - /* S4OS is only supported for now via swsusp.. */ - if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) { - if (!acpi_wakeup_address) - return -EFAULT; - acpi_set_firmware_waking_vector( - (acpi_physical_address) virt_to_phys( - (void *)acpi_wakeup_address)); } - ACPI_FLUSH_CPU_CACHE(); - acpi_enable_wakeup_device_prep(acpi_state); - acpi_enter_sleep_state_prep(acpi_state); - return 0; + return acpi_sleep_prepare(acpi_state); } - /** * acpi_pm_enter - Actually enter a sleep state. * @pm_state: State we're entering. @@ -92,11 +83,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) return error; } - local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); - switch (pm_state) - { + switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); status = acpi_enter_sleep_state(acpi_state); @@ -112,6 +101,10 @@ static int acpi_pm_enter(suspend_state_t pm_state) else do_suspend_lowlevel_s4bios(); break; + case PM_SUSPEND_MAX: + acpi_power_off(); + break; + default: return -EINVAL; } @@ -126,11 +119,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); - return ACPI_SUCCESS(status) ? 0 : -EFAULT; } - /** * acpi_pm_finish - Finish up suspend sequence. * @pm_state: State we're coming out of. @@ -156,27 +147,26 @@ static int acpi_pm_finish(suspend_state_t pm_state) return 0; } - int acpi_suspend(u32 acpi_state) { suspend_state_t states[] = { - [1] = PM_SUSPEND_STANDBY, - [3] = PM_SUSPEND_MEM, - [4] = PM_SUSPEND_DISK, + [1] = PM_SUSPEND_STANDBY, + [3] = PM_SUSPEND_MEM, + [4] = PM_SUSPEND_DISK, + [5] = PM_SUSPEND_MAX }; - if (acpi_state <= 4 && states[acpi_state]) + if (acpi_state < 6 && states[acpi_state]) return pm_suspend(states[acpi_state]); return -EINVAL; } static struct pm_ops acpi_pm_ops = { - .prepare = acpi_pm_prepare, - .enter = acpi_pm_enter, - .finish = acpi_pm_finish, + .prepare = acpi_pm_prepare, + .enter = acpi_pm_enter, + .finish = acpi_pm_finish, }; - /* * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. @@ -190,16 +180,16 @@ static int __init init_ints_after_s1(struct dmi_system_id *d) static struct dmi_system_id __initdata acpisleep_dmi_table[] = { { - .callback = init_ints_after_s1, - .ident = "Toshiba Satellite 4030cdt", - .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), }, - }, - { }, + .callback = init_ints_after_s1, + .ident = "Toshiba Satellite 4030cdt", + .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, + }, + {}, }; static int __init acpi_sleep_init(void) { - int i = 0; + int i = 0; dmi_check_system(acpisleep_dmi_table); @@ -207,7 +197,7 @@ static int __init acpi_sleep_init(void) return 0; printk(KERN_INFO PREFIX "(supports"); - for (i=0; i < ACPI_S_STATE_COUNT; i++) { + for (i = 0; i < ACPI_S_STATE_COUNT; i++) { acpi_status status; u8 type_a, type_b; status = acpi_get_sleep_type_data(i, &type_a, &type_b); diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index da237754ded..1fc86e6b5ab 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -3,35 +3,100 @@ * * AKA S5, but it is independent of whether or not the kernel supports * any other sleep support in the system. + * + * Copyright (c) 2005 Alexey Starikovskiy + * + * This file is released under the GPLv2. */ #include #include #include #include +#include +#include #include "sleep.h" -static void -acpi_power_off (void) +int acpi_sleep_prepare(u32 acpi_state) +{ + /* Flag to do not allow second time invocation for S5 state */ + static int shutdown_prepared = 0; +#ifdef CONFIG_ACPI_SLEEP + /* do we have a wakeup address for S2 and S3? */ + /* Here, we support only S4BIOS, those we set the wakeup address */ + /* S4OS is only supported for now via swsusp.. */ + if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { + if (!acpi_wakeup_address) { + return -EFAULT; + } + acpi_set_firmware_waking_vector((acpi_physical_address) + virt_to_phys((void *) + acpi_wakeup_address)); + + } + ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); +#endif + if (acpi_state == ACPI_STATE_S5) { + /* Check if we were already called */ + if (shutdown_prepared) + return 0; + acpi_wakeup_gpe_poweroff_prepare(); + shutdown_prepared = 1; + } + acpi_enter_sleep_state_prep(acpi_state); + return 0; +} + +void acpi_power_off(void) { - printk("%s called\n",__FUNCTION__); + printk("%s called\n", __FUNCTION__); + acpi_sleep_prepare(ACPI_STATE_S5); + local_irq_disable(); /* Some SMP machines only can poweroff in boot CPU */ set_cpus_allowed(current, cpumask_of_cpu(0)); - acpi_wakeup_gpe_poweroff_prepare(); - acpi_enter_sleep_state_prep(ACPI_STATE_S5); - ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); } +#ifdef CONFIG_PM + +static int acpi_shutdown(struct sys_device *x) +{ + return acpi_sleep_prepare(ACPI_STATE_S5); +} + +static struct sysdev_class acpi_sysclass = { + set_kset_name("acpi"), + .shutdown = acpi_shutdown +}; + +static struct sys_device device_acpi = { + .id = 0, + .cls = &acpi_sysclass, +}; + +#endif + static int acpi_poweroff_init(void) { if (!acpi_disabled) { u8 type_a, type_b; acpi_status status; - status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) + status = + acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); + if (ACPI_SUCCESS(status)) { pm_power_off = acpi_power_off; +#ifdef CONFIG_PM + { + int error; + error = sysdev_class_register(&acpi_sysclass); + if (!error) + error = sysdev_register(&device_acpi); + return error; + } +#endif + } } return 0; } diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9102e3756f9..5474bf9622d 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -22,7 +22,6 @@ #include #include - extern struct subsystem devices_subsys; #define to_sysdev(k) container_of(k, struct sys_device, kobj) -- cgit v1.2.3 From 362b06bb70b5a5779b2e852e0f2bdb437061106e Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 16:30:29 -0500 Subject: [ACPI] S3 Suspend to RAM: interrupt resume fix Delete PCI Interrupt Link Device .resume method -- it is the device driver's job to request interrupts, not the Link's job to remember what the devices want. This addresses the issue of attempting to run the ACPI interpreter too early in resume, when interrupts are still disabled. http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 520b28ad074..f2271173bbd 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -72,10 +72,12 @@ struct acpi_pci_link_irq { u8 active; /* Current IRQ */ u8 edge_level; /* All IRQs */ u8 active_high_low; /* All IRQs */ - u8 initialized; u8 resource_type; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; + u8 initialized:1; + u8 suspend_resume:1; + u8 reserved:6; }; struct acpi_pci_link { @@ -530,6 +532,10 @@ static int acpi_pci_link_allocate( ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); + if (link->irq.suspend_resume) { + acpi_pci_link_set(link, link->irq.active); + link->irq.suspend_resume = 0; + } if (link->irq.initialized) return_VALUE(0); @@ -713,38 +719,24 @@ end: return_VALUE(result); } - -static int -acpi_pci_link_resume ( - struct acpi_pci_link *link) -{ - ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); - - if (link->irq.active && link->irq.initialized) - return_VALUE(acpi_pci_link_set(link, link->irq.active)); - else - return_VALUE(0); -} - - static int -irqrouter_resume( - struct sys_device *dev) +irqrouter_suspend( + struct sys_device *dev, + u32 state) { struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - ACPI_FUNCTION_TRACE("irqrouter_resume"); + ACPI_FUNCTION_TRACE("irqrouter_suspend"); list_for_each(node, &acpi_link.entries) { - link = list_entry(node, struct acpi_pci_link, node); if (!link) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); continue; } - - acpi_pci_link_resume(link); + if (link->irq.active && link->irq.initialized) + link->irq.suspend_resume = 1; } return_VALUE(0); } @@ -856,7 +848,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); static struct sysdev_class irqrouter_sysdev_class = { set_kset_name("irqrouter"), - .resume = irqrouter_resume, + .suspend = irqrouter_suspend, }; -- cgit v1.2.3 From d58da590451cf6ae75379a2ebf96d3afb8d810d8 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 16:43:54 -0500 Subject: [ACPI] S3 Suspend to RAM: fix driver suspend/resume methods Drivers should do this: .suspend() pci_disable_device() .resume() pci_enable_device() http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/net/b44.c | 3 +++ drivers/net/ne2k-pci.c | 3 +++ drivers/pcmcia/yenta_socket.c | 3 +++ drivers/usb/core/hcd-pci.c | 1 + 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 3fe8ba992c3..38844d003e4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1927,6 +1927,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); + pci_disable_device(pdev); return 0; } @@ -1936,6 +1937,8 @@ static int b44_resume(struct pci_dev *pdev) struct b44 *bp = netdev_priv(dev); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); if (!netif_running(dev)) return 0; diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index a1a6c08e7dc..f1c01ac2910 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -660,6 +660,7 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); pci_save_state(pdev); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -671,6 +672,8 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6404d97a12e..caf7159a54b 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1032,6 +1032,7 @@ static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) pci_save_state(dev); pci_read_config_dword(dev, 16*4, &socket->saved_state[0]); pci_read_config_dword(dev, 17*4, &socket->saved_state[1]); + pci_disable_device(dev); /* * Some laptops (IBM T22) do not like us putting the Cardbus @@ -1055,6 +1056,8 @@ static int yenta_dev_resume (struct pci_dev *dev) pci_restore_state(dev); pci_write_config_dword(dev, 16*4, socket->saved_state[0]); pci_write_config_dword(dev, 17*4, socket->saved_state[1]); + pci_enable_device(dev); + pci_set_master(dev); if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 71b4a8d6631..fc056062c96 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -380,6 +380,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) usb_hc_died (hcd); } + pci_enable_device(dev); return retval; } EXPORT_SYMBOL (usb_hcd_pci_resume); -- cgit v1.2.3 From fb9802fa59b196d7f90bb3c2e33c555c6bdc4c54 Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Fri, 18 Mar 2005 18:03:45 -0500 Subject: [ACPI] generic Hot Key support See Documentation/acpi-hotkey.txt Use cmdline "acpi_specific_hotkey" to enable legacy platform specific drivers. http://bugzilla.kernel.org/show_bug.cgi?id=3887 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 9 + drivers/acpi/Makefile | 3 +- drivers/acpi/asus_acpi.c | 4 + drivers/acpi/hotkey.c | 1018 +++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/ibm_acpi.c | 4 + drivers/acpi/osl.c | 12 + drivers/acpi/toshiba_acpi.c | 5 + 7 files changed, 1054 insertions(+), 1 deletion(-) create mode 100644 drivers/acpi/hotkey.c (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ceecc5634e7..fa7f4345189 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -123,6 +123,15 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. +config ACPI_HOTKEY + tristate "Generic Hotkey" + depends on ACPI_INTERPRETER + depends on EXPERIMENTAL + depends on !IA64_SGI_SN + default m + help + ACPI generic hotkey + config ACPI_FAN tristate "Fan" depends on !IA64_SGI_SN diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 65c92e20566..24eb397e17b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,7 +42,8 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o -obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index a75cb565cae..a560b1e2da7 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -1204,6 +1204,10 @@ static int __init asus_acpi_init(void) if (acpi_disabled) return -ENODEV; + if (!acpi_specific_hotkey_enabled){ + printk(KERN_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c new file mode 100644 index 00000000000..0aef9fc449c --- /dev/null +++ b/drivers/acpi/hotkey.c @@ -0,0 +1,1018 @@ +/* + * hotkey.c - ACPI Hotkey Driver ($Revision:$) + * + * Copyright (C) 2004 Luming Yu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + +#define HOTKEY_ACPI_VERSION "0.1" + +#define HOTKEY_PROC "hotkey" +#define HOTKEY_EV_CONFIG "event_config" +#define HOTKEY_PL_CONFIG "poll_config" +#define HOTKEY_ACTION "action" +#define HOTKEY_INFO "info" + +#define ACPI_HOTK_NAME "Generic Hotkey Driver" +#define ACPI_HOTK_CLASS "Hotkey" +#define ACPI_HOTK_DEVICE_NAME "Hotkey" +#define ACPI_HOTK_HID "Unknown?" +#define ACPI_HOTKEY_COMPONENT 0x20000000 + +#define ACPI_HOTKEY_EVENT 0x1 +#define ACPI_HOTKEY_POLLING 0x2 +#define ACPI_UNDEFINED_EVENT 0xf + +#define MAX_CONFIG_RECORD_LEN 80 +#define MAX_NAME_PATH_LEN 80 +#define MAX_CALL_PARM 80 + +#define IS_EVENT(e) 0xff /* ((e) & 0x40000000) */ +#define IS_POLL(e) 0xff /* (~((e) & 0x40000000)) */ + +#define _COMPONENT ACPI_HOTKEY_COMPONENT +ACPI_MODULE_NAME("acpi_hotkey") + + MODULE_AUTHOR("luming.yu@intel.com"); +MODULE_DESCRIPTION(ACPI_HOTK_NAME); +MODULE_LICENSE("GPL"); + +/* standardized internal hotkey number/event */ +enum { + /* Video Extension event */ + HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, + HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, + HK_EVENT_CYCLE_DISPLAY_OUTPUT, + HK_EVENT_NEXT_DISPLAY_OUTPUT, + HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, + HK_EVENT_CYCLE_BRIGHTNESS, + HK_EVENT_INCREASE_BRIGHTNESS, + HK_EVENT_DECREASE_BRIGHTNESS, + HK_EVENT_ZERO_BRIGHTNESS, + HK_EVENT_DISPLAY_DEVICE_OFF, + + /* Snd Card event */ + HK_EVENT_VOLUME_MUTE, + HK_EVENT_VOLUME_INCLREASE, + HK_EVENT_VOLUME_DECREASE, + + /* running state control */ + HK_EVENT_ENTERRING_S3, + HK_EVENT_ENTERRING_S4, + HK_EVENT_ENTERRING_S5, +}; + +/* procdir we use */ +static struct proc_dir_entry *hotkey_proc_dir; +static struct proc_dir_entry *hotkey_config; +static struct proc_dir_entry *hotkey_poll_config; +static struct proc_dir_entry *hotkey_action; +static struct proc_dir_entry *hotkey_info; + +/* linkage for all type of hotkey */ +struct acpi_hotkey_link { + struct list_head entries; + int hotkey_type; /* event or polling based hotkey */ + int hotkey_standard_num; /* standardized hotkey(event) number */ +}; + +/* event based hotkey */ +struct acpi_event_hotkey { + struct acpi_hotkey_link hotkey_link; + int flag; + acpi_handle bus_handle; /* bus to install notify handler */ + int external_hotkey_num; /* external hotkey/event number */ + acpi_handle action_handle; /* acpi handle attached aml action method */ + char *action_method; /* action method */ +}; + +/* + * There are two ways to poll status + * 1. directy call read_xxx method, without any arguments passed in + * 2. call write_xxx method, with arguments passed in, you need + * the result is saved in acpi_polling_hotkey.poll_result. + * anthoer read command through polling interface. + * + */ + +/* polling based hotkey */ +struct acpi_polling_hotkey { + struct acpi_hotkey_link hotkey_link; + int flag; + acpi_handle poll_handle; /* acpi handle attached polling method */ + char *poll_method; /* poll method */ + acpi_handle action_handle; /* acpi handle attached action method */ + char *action_method; /* action method */ + void *poll_result; /* polling_result */ + struct proc_dir_entry *proc; +}; + +/* hotkey object union */ +union acpi_hotkey { + struct list_head entries; + struct acpi_hotkey_link link; + struct acpi_event_hotkey event_hotkey; + struct acpi_polling_hotkey poll_hotkey; +}; + +/* hotkey object list */ +struct acpi_hotkey_list { + struct list_head *entries; + int count; +}; + +static int auto_hotkey_add(struct acpi_device *device); +static int auto_hotkey_remove(struct acpi_device *device, int type); + +static struct acpi_driver hotkey_driver = { + .name = ACPI_HOTK_NAME, + .class = ACPI_HOTK_CLASS, + .ids = ACPI_HOTK_HID, + .ops = { + .add = auto_hotkey_add, + .remove = auto_hotkey_remove, + }, +}; + +static int hotkey_open_config(struct inode *inode, struct file *file); +static ssize_t hotkey_write_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static ssize_t hotkey_write_poll_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static int hotkey_info_open_fs(struct inode *inode, struct file *file); +static int hotkey_action_open_fs(struct inode *inode, struct file *file); +static ssize_t hotkey_execute_aml_method(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static int hotkey_config_seq_show(struct seq_file *seq, void *offset); +static int hotkey_polling_open_fs(struct inode *inode, struct file *file); + +/* event based config */ +static struct file_operations hotkey_config_fops = { + .open = hotkey_open_config, + .read = seq_read, + .write = hotkey_write_config, + .llseek = seq_lseek, + .release = single_release, +}; + +/* polling based config */ +static struct file_operations hotkey_poll_config_fops = { + .open = hotkey_open_config, + .read = seq_read, + .write = hotkey_write_poll_config, + .llseek = seq_lseek, + .release = single_release, +}; + +/* hotkey driver info */ +static struct file_operations hotkey_info_fops = { + .open = hotkey_info_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* action */ +static struct file_operations hotkey_action_fops = { + .open = hotkey_action_open_fs, + .read = seq_read, + .write = hotkey_execute_aml_method, + .llseek = seq_lseek, + .release = single_release, +}; + +/* polling results */ +static struct file_operations hotkey_polling_fops = { + .open = hotkey_polling_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ +struct list_head hotkey_entries; /* head of the list of hotkey_list */ + +static int hotkey_info_seq_show(struct seq_file *seq, void *offset) +{ + ACPI_FUNCTION_TRACE("hotkey_info_seq_show"); + + seq_printf(seq, "Hotkey generic driver ver: %s", HOTKEY_ACPI_VERSION); + + return_VALUE(0); +} + +static int hotkey_info_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_info_seq_show, PDE(inode)->data); +} + +static char *format_result(union acpi_object *object) +{ + char *buf = (char *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); + + memset(buf, 0, sizeof(union acpi_object)); + + /* Now, just support integer type */ + if (object->type == ACPI_TYPE_INTEGER) + sprintf(buf, "%d", (u32) object->integer.value); + + return buf; +} + +static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_polling_hotkey *poll_hotkey = + (struct acpi_polling_hotkey *)seq->private; + + ACPI_FUNCTION_TRACE("hotkey_polling_seq_show"); + + if (poll_hotkey->poll_result) + seq_printf(seq, "%s", format_result(poll_hotkey->poll_result)); + + return_VALUE(0); +} + +static int hotkey_polling_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); +} + +static int hotkey_action_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_info_seq_show, PDE(inode)->data); +} + +/* Mapping external hotkey number to standardized hotkey event num */ +static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) +{ + struct list_head *entries, *next; + int val = 0; + + ACPI_FUNCTION_TRACE("hotkey_get_internal_event"); + + list_for_each_safe(entries, next, list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT + && key->event_hotkey.external_hotkey_num == event) + val = key->link.hotkey_standard_num; + else + val = -1; + } + + return_VALUE(val); +} + +static void +acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *device = NULL; + u32 internal_event; + + ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler"); + + if (acpi_bus_get_device(handle, &device)) + return_VOID; + + internal_event = hotkey_get_internal_event(event, &global_hotkey_list); + acpi_bus_generate_event(device, event, 0); + + return_VOID; +} + +/* Need to invent automatically hotkey add method */ +static int auto_hotkey_add(struct acpi_device *device) +{ + /* Implement me */ + return 0; +} + +/* Need to invent automatically hotkey remove method */ +static int auto_hotkey_remove(struct acpi_device *device, int type) +{ + /* Implement me */ + return 0; +} + +/* Create a proc file for each polling method */ +static int create_polling_proc(union acpi_hotkey *device) +{ + struct proc_dir_entry *proc; + + ACPI_FUNCTION_TRACE("create_polling_proc"); + mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + + proc = create_proc_entry(device->poll_hotkey.action_method, + mode, hotkey_proc_dir); + + if (!proc) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + device->poll_hotkey.poll_method)); + return_VALUE(-ENODEV); + } else { + proc->proc_fops = &hotkey_polling_fops; + proc->owner = THIS_MODULE; + proc->data = device; + proc->uid = 0; + proc->gid = 0; + device->poll_hotkey.proc = proc; + } + return_VALUE(0); +} + +static int is_valid_acpi_path(const char *pathname) +{ + acpi_handle handle; + acpi_status status; + ACPI_FUNCTION_TRACE("is_valid_acpi_path"); + + status = acpi_get_handle(NULL, (char *)pathname, &handle); + return_VALUE(!ACPI_FAILURE(status)); +} + +static int is_valid_hotkey(union acpi_hotkey *device) +{ + ACPI_FUNCTION_TRACE("is_valid_hotkey"); + /* Implement valid check */ + return_VALUE(1); +} + +static int hotkey_add(union acpi_hotkey *device) +{ + int status = 0; + struct acpi_device *dev = NULL; + + ACPI_FUNCTION_TRACE("hotkey_add"); + + if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { + status = + acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); + if (status) + return_VALUE(status); + + status = acpi_install_notify_handler(dev->handle, + ACPI_SYSTEM_NOTIFY, + acpi_hotkey_notify_handler, + device); + } else /* Add polling hotkey */ + create_polling_proc(device); + + global_hotkey_list.count++; + + list_add_tail(&device->link.entries, global_hotkey_list.entries); + + return_VALUE(status); +} + +static int hotkey_remove(union acpi_hotkey *device) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_remove"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_standard_num == + device->link.hotkey_standard_num) { + list_del(&key->link.entries); + remove_proc_entry(key->poll_hotkey.action_method, + hotkey_proc_dir); + global_hotkey_list.count--; + break; + } + } + return_VALUE(0); +} + +static void hotkey_update(union acpi_hotkey *key) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_update"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_standard_num == + key->link.hotkey_standard_num) { + key->event_hotkey.bus_handle = + key->event_hotkey.bus_handle; + key->event_hotkey.external_hotkey_num = + key->event_hotkey.external_hotkey_num; + key->event_hotkey.action_handle = + key->event_hotkey.action_handle; + key->event_hotkey.action_method = + key->event_hotkey.action_method; + break; + } + } + + return_VOID; +} + +static void free_hotkey_device(union acpi_hotkey *key) +{ + struct acpi_device *dev; + int status; + + ACPI_FUNCTION_TRACE("free_hotkey_device"); + + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { + status = + acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); + if (dev->handle) + acpi_remove_notify_handler(dev->handle, + ACPI_SYSTEM_NOTIFY, + acpi_hotkey_notify_handler); + } else + remove_proc_entry(key->poll_hotkey.action_method, + hotkey_proc_dir); + kfree(key); + return_VOID; +} + +static int +init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str, + char *method, int std_num, int external_num) +{ + ACPI_FUNCTION_TRACE("init_hotkey_device"); + + key->link.hotkey_type = ACPI_HOTKEY_EVENT; + key->link.hotkey_standard_num = std_num; + key->event_hotkey.flag = 0; + if (is_valid_acpi_path(bus_str)) + acpi_get_handle((acpi_handle) 0, + bus_str, &(key->event_hotkey.bus_handle)); + else + return_VALUE(-ENODEV); + key->event_hotkey.external_hotkey_num = external_num; + if (is_valid_acpi_path(action_str)) + acpi_get_handle((acpi_handle) 0, + action_str, &(key->event_hotkey.action_handle)); + key->event_hotkey.action_method = kmalloc(sizeof(method), GFP_KERNEL); + strcpy(key->event_hotkey.action_method, method); + + return_VALUE(!is_valid_hotkey(key)); +} + +static int +init_poll_hotkey_device(union acpi_hotkey *key, + char *poll_str, + char *poll_method, + char *action_str, char *action_method, int std_num) +{ + ACPI_FUNCTION_TRACE("init_poll_hotkey_device"); + + key->link.hotkey_type = ACPI_HOTKEY_POLLING; + key->link.hotkey_standard_num = std_num; + key->poll_hotkey.flag = 0; + if (is_valid_acpi_path(poll_str)) + acpi_get_handle((acpi_handle) 0, + poll_str, &(key->poll_hotkey.poll_handle)); + else + return_VALUE(-ENODEV); + key->poll_hotkey.poll_method = poll_method; + if (is_valid_acpi_path(action_str)) + acpi_get_handle((acpi_handle) 0, + action_str, &(key->poll_hotkey.action_handle)); + key->poll_hotkey.action_method = + kmalloc(sizeof(action_method), GFP_KERNEL); + strcpy(key->poll_hotkey.action_method, action_method); + key->poll_hotkey.poll_result = + (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); + return_VALUE(is_valid_hotkey(key)); +} + +static int check_hotkey_valid(union acpi_hotkey *key, + struct acpi_hotkey_list *list) +{ + ACPI_FUNCTION_TRACE("check_hotkey_valid"); + return_VALUE(0); +} + +static int hotkey_open_config(struct inode *inode, struct file *file) +{ + ACPI_FUNCTION_TRACE("hotkey_open_config"); + return_VALUE(single_open + (file, hotkey_config_seq_show, PDE(inode)->data)); +} + +static int hotkey_config_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + struct list_head *entries, *next; + char bus_name[ACPI_PATHNAME_MAX] = { 0 }; + char action_name[ACPI_PATHNAME_MAX] = { 0 }; + struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; + struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; + + ACPI_FUNCTION_TRACE(("hotkey_config_seq_show")); + + if (!hotkey_list) + goto end; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { + acpi_get_name(key->event_hotkey.bus_handle, + ACPI_NAME_TYPE_MAX, &bus); + acpi_get_name(key->event_hotkey.action_handle, + ACPI_NAME_TYPE_MAX, &act); + seq_printf(seq, "%s:%s:%s:%d:%d", bus_name, + action_name, + key->event_hotkey.action_method, + key->link.hotkey_standard_num, + key->event_hotkey.external_hotkey_num); + } /* ACPI_HOTKEY_POLLING */ + else { + acpi_get_name(key->poll_hotkey.poll_handle, + ACPI_NAME_TYPE_MAX, &bus); + acpi_get_name(key->poll_hotkey.action_handle, + ACPI_NAME_TYPE_MAX, &act); + seq_printf(seq, "%s:%s:%s:%s:%d", bus_name, + key->poll_hotkey.poll_method, + action_name, + key->poll_hotkey.action_method, + key->link.hotkey_standard_num); + } + } + seq_puts(seq, "\n"); + end: + return_VALUE(0); +} + +static int +get_parms(char *config_record, + int *cmd, + char *bus_handle, + char *bus_method, + char *action_handle, + char *method, int *internal_event_num, int *external_event_num) +{ + char *tmp, *tmp1; + ACPI_FUNCTION_TRACE(("get_parms")); + + sscanf(config_record, "%d", cmd); + + tmp = strchr(config_record, ':'); + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(bus_handle, tmp, tmp1 - tmp); + bus_handle[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(bus_method, tmp, tmp1 - tmp); + bus_method[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(action_handle, tmp, tmp1 - tmp); + action_handle[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(method, tmp, tmp1 - tmp); + method[tmp1 - tmp] = 0; + + sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num); + return_VALUE(6); +} + +/* count is length for one input record */ +static ssize_t hotkey_write_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + char config_record[MAX_CONFIG_RECORD_LEN]; + char bus_handle[MAX_NAME_PATH_LEN]; + char bus_method[MAX_NAME_PATH_LEN]; + char action_handle[MAX_NAME_PATH_LEN]; + char method[20]; + int cmd, internal_event_num, external_event_num; + int ret = 0; + union acpi_hotkey *key = NULL; + + ACPI_FUNCTION_TRACE(("hotkey_write_config")); + + if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(config_record, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n")); + return_VALUE(-EINVAL); + } + config_record[count] = '\0'; + + ret = get_parms(config_record, + &cmd, + bus_handle, + bus_method, + action_handle, + method, &internal_event_num, &external_event_num); + if (ret != 6) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid data format ret=%d\n", ret)); + return_VALUE(-EINVAL); + } + + key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); + ret = init_hotkey_device(key, bus_handle, action_handle, method, + internal_event_num, external_event_num); + + if (ret || check_hotkey_valid(key, hotkey_list)) { + kfree(key); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n")); + return_VALUE(-EINVAL); + } + switch (cmd) { + case 0: + hotkey_add(key); + break; + case 1: + hotkey_remove(key); + free_hotkey_device(key); + break; + case 2: + hotkey_update(key); + break; + default: + break; + } + return_VALUE(count); +} + +/* count is length for one input record */ +static ssize_t hotkey_write_poll_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + struct acpi_hotkey_list *hotkey_list = + (struct acpi_hotkey_list *)m->private; + + char config_record[MAX_CONFIG_RECORD_LEN]; + char polling_handle[MAX_NAME_PATH_LEN]; + char action_handle[MAX_NAME_PATH_LEN]; + char poll_method[20], action_method[20]; + int ret, internal_event_num, cmd, external_event_num; + union acpi_hotkey *key = NULL; + + ACPI_FUNCTION_TRACE("hotkey_write_poll_config"); + + if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(config_record, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n")); + return_VALUE(-EINVAL); + } + config_record[count] = '\0'; + + ret = get_parms(config_record, + &cmd, + polling_handle, + poll_method, + action_handle, + action_method, + &internal_event_num, &external_event_num); + + if (ret != 6) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); + return_VALUE(-EINVAL); + } + + key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); + ret = init_poll_hotkey_device(key, polling_handle, poll_method, + action_handle, action_method, + internal_event_num); + if (ret || check_hotkey_valid(key, hotkey_list)) { + kfree(key); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n")); + return_VALUE(-EINVAL); + } + switch (cmd) { + case 0: + hotkey_add(key); + break; + case 1: + hotkey_remove(key); + break; + case 2: + hotkey_update(key); + break; + default: + break; + } + return_VALUE(count); +} + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; /* list of input parameters (an int here) */ + union acpi_object in_obj; /* the only param we use */ + acpi_status status; + + ACPI_FUNCTION_TRACE("write_acpi_int"); + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); + + return_VALUE(status == AE_OK); +} + +static int read_acpi_int(acpi_handle handle, const char *method, int *val) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + ACPI_FUNCTION_TRACE("read_acpi_int"); + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char *)method, NULL, &output); + *val = out_obj.integer.value; + return_VALUE((status == AE_OK) + && (out_obj.type == ACPI_TYPE_INTEGER)); +} + +static acpi_handle +get_handle_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, int event_num) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT + && key->link.hotkey_standard_num == event_num) { + return (key->event_hotkey.action_handle); + } + } + return (NULL); +} + +static +char *get_method_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, + int event_num) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT && + key->link.hotkey_standard_num == event_num) + return (key->event_hotkey.action_method); + } + return (NULL); +} + +static struct acpi_polling_hotkey *get_hotkey_by_event(struct + acpi_hotkey_list + *hotkey_list, int event) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_POLLING + && key->link.hotkey_standard_num == event) { + return (&key->poll_hotkey); + } + } + return (NULL); +} + +/* + * user call AML method interface: + * Call convention: + * echo "event_num: arg type : value" + * example: echo "1:1:30" > /proc/acpi/action + * Just support 1 integer arg passing to AML method + */ + +static ssize_t hotkey_execute_aml_method(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + char arg[MAX_CALL_PARM]; + int event, type, value; + + char *method; + acpi_handle handle; + + ACPI_FUNCTION_TRACE("hotkey_execte_aml_method"); + + if (!hotkey_list || count > MAX_CALL_PARM) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 1")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(arg, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2")); + return_VALUE(-EINVAL); + } + + arg[count] = '\0'; + + if (sscanf(arg, "%d:%d:%d", &event, &type, &value) != 3) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3")); + return_VALUE(-EINVAL); + } + + if (type == ACPI_TYPE_INTEGER) { + handle = get_handle_from_hotkeylist(hotkey_list, event); + method = (char *)get_method_from_hotkeylist(hotkey_list, event); + if (IS_EVENT(event)) + write_acpi_int(handle, method, value, NULL); + else if (IS_POLL(event)) { + struct acpi_polling_hotkey *key; + key = (struct acpi_polling_hotkey *) + get_hotkey_by_event(hotkey_list, event); + read_acpi_int(handle, method, key->poll_result); + } + } else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported")); + return_VALUE(-EINVAL); + } + + return_VALUE(count); +} + +static int __init hotkey_init(void) +{ + int result; + mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + + ACPI_FUNCTION_TRACE("hotkey_init"); + + if (acpi_disabled) + return -ENODEV; + + if (acpi_specific_hotkey_enabled) { + printk("Using specific hotkey driver\n"); + return -ENODEV; + } + + hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); + if (!hotkey_proc_dir) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_PROC)); + return (-ENODEV); + } + hotkey_proc_dir->owner = THIS_MODULE; + + hotkey_config = + create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); + if (!hotkey_config) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_EV_CONFIG)); + return (-ENODEV); + } else { + hotkey_config->proc_fops = &hotkey_config_fops; + hotkey_config->data = &global_hotkey_list; + hotkey_config->owner = THIS_MODULE; + hotkey_config->uid = 0; + hotkey_config->gid = 0; + } + + hotkey_poll_config = + create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); + if (!hotkey_poll_config) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_EV_CONFIG)); + return (-ENODEV); + } else { + hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; + hotkey_poll_config->data = &global_hotkey_list; + hotkey_poll_config->owner = THIS_MODULE; + hotkey_poll_config->uid = 0; + hotkey_poll_config->gid = 0; + } + + hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); + if (!hotkey_action) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_ACTION)); + return (-ENODEV); + } else { + hotkey_action->proc_fops = &hotkey_action_fops; + hotkey_action->owner = THIS_MODULE; + hotkey_action->uid = 0; + hotkey_action->gid = 0; + } + + hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); + if (!hotkey_info) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_INFO)); + return (-ENODEV); + } else { + hotkey_info->proc_fops = &hotkey_info_fops; + hotkey_info->owner = THIS_MODULE; + hotkey_info->uid = 0; + hotkey_info->gid = 0; + } + + result = acpi_bus_register_driver(&hotkey_driver); + if (result < 0) { + remove_proc_entry(HOTKEY_PROC, acpi_root_dir); + return (-ENODEV); + } + global_hotkey_list.count = 0; + global_hotkey_list.entries = &hotkey_entries; + + INIT_LIST_HEAD(&hotkey_entries); + + return (0); +} + +static void __exit hotkey_exit(void) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_remove"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + + acpi_os_wait_events_complete(NULL); + list_del(&key->link.entries); + global_hotkey_list.count--; + free_hotkey_device(key); + } + acpi_bus_unregister_driver(&hotkey_driver); + remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); + remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); + remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); + remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); + remove_proc_entry(HOTKEY_PROC, acpi_root_dir); + return; +} + +module_init(hotkey_init); +module_exit(hotkey_exit); diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 0fb731a470d..6c8291c3e77 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1185,6 +1185,10 @@ static int __init acpi_ibm_init(void) if (acpi_disabled) return -ENODEV; + if (!acpi_specific_hotkey_enabled){ + printk(IBM_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } /* these handles are required */ if (IBM_HANDLE_INIT(ec, 1) < 0 || IBM_HANDLE_INIT(hkey, 1) < 0 || diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5a9128de622..bdd9f37f810 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -71,6 +71,9 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER*/ +int acpi_specific_hotkey_enabled; +EXPORT_SYMBOL(acpi_specific_hotkey_enabled); + static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -1152,6 +1155,15 @@ acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); +int __init +acpi_hotkey_setup(char *str) +{ + acpi_specific_hotkey_enabled = TRUE; + return 1; +} + +__setup("acpi_specific_hotkey", acpi_hotkey_setup); + /* * max_cstate is defined in the base kernel so modules can * change it w/o depending on the state of the processor module. diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index c84997c9f96..bed8e53a5ee 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -529,6 +529,11 @@ toshiba_acpi_init(void) if (acpi_disabled) return -ENODEV; + + if (!acpi_specific_hotkey_enabled){ + printk(MY_INFO "Using generic hotkey driver\n"); + return -ENODEV; + } /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; -- cgit v1.2.3 From 4e10d12a3d88c88fba3258809aa42d14fd8cf1d1 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 18:45:35 -0500 Subject: [ACPI] Bind PCI devices with ACPI devices Implement the framework for binding physical devices with ACPI devices. A physical bus like PCI bus should create a 'acpi_bus_type', with: .find_device: For device which has parent such as normal PCI devices. .find_bridge: It's for special devices, such as PCI root bridge or IDE controller. Such devices generally haven't a parent or ->bus. We use the special method to get an ACPI handle. Uses new field in struct device: firmware_data http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/Makefile | 2 +- drivers/acpi/glue.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/ibm_acpi.c | 4 +- 3 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 drivers/acpi/glue.c (limited to 'drivers') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 24eb397e17b..ad67e8f61e6 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -36,7 +36,7 @@ processor-objs += processor_perflib.o endif obj-$(CONFIG_ACPI_BUS) += sleep/ -obj-$(CONFIG_ACPI_BUS) += bus.o +obj-$(CONFIG_ACPI_BUS) += bus.o glue.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c new file mode 100644 index 00000000000..b6d2045caf3 --- /dev/null +++ b/drivers/acpi/glue.c @@ -0,0 +1,362 @@ +/* + * Link physical devices with ACPI devices support + * + * Copyright (c) 2005 David Shaohua Li + * Copyright (c) 2005 Intel Corp. + * + * This file is released under the GPLv2. + */ +#include +#include +#include +#include +#include + +#define ACPI_GLUE_DEBUG 0 +#if ACPI_GLUE_DEBUG +#define DBG(x...) printk(PREFIX x) +#else +#define DBG(x...) +#endif +static LIST_HEAD(bus_type_list); +static DECLARE_RWSEM(bus_type_sem); + +int register_acpi_bus_type(struct acpi_bus_type *type) +{ + if (acpi_disabled) + return -ENODEV; + if (type && type->bus && type->find_device) { + down_write(&bus_type_sem); + list_add_tail(&type->list, &bus_type_list); + up_write(&bus_type_sem); + DBG("ACPI bus type %s registered\n", type->bus->name); + return 0; + } + return -ENODEV; +} + +EXPORT_SYMBOL(register_acpi_bus_type); + +int unregister_acpi_bus_type(struct acpi_bus_type *type) +{ + if (acpi_disabled) + return 0; + if (type) { + down_write(&bus_type_sem); + list_del_init(&type->list); + up_write(&bus_type_sem); + DBG("ACPI bus type %s unregistered\n", type->bus->name); + return 0; + } + return -ENODEV; +} + +EXPORT_SYMBOL(unregister_acpi_bus_type); + +static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) +{ + struct acpi_bus_type *tmp, *ret = NULL; + + down_read(&bus_type_sem); + list_for_each_entry(tmp, &bus_type_list, list) { + if (tmp->bus == type) { + ret = tmp; + break; + } + } + up_read(&bus_type_sem); + return ret; +} + +static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) +{ + struct acpi_bus_type *tmp; + int ret = -ENODEV; + + down_read(&bus_type_sem); + list_for_each_entry(tmp, &bus_type_list, list) { + if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { + ret = 0; + break; + } + } + up_read(&bus_type_sem); + return ret; +} + +/* Get PCI root bridge's handle from its segment and bus number */ +struct acpi_find_pci_root { + unsigned int seg; + unsigned int bus; + acpi_handle handle; +}; + +static acpi_status +do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) +{ + int *busnr = (int *)data; + struct acpi_resource_address64 address; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + if ((address.address_length > 0) && + (address.resource_type == ACPI_BUS_NUMBER_RANGE)) + *busnr = address.min_address_range; + + return AE_OK; +} + +static int get_root_bridge_busnr(acpi_handle handle) +{ + acpi_status status; + int bus, bbn; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, + (unsigned long *)&bbn); + if (status == AE_NOT_FOUND) { + /* Assume bus = 0 */ + printk(KERN_INFO PREFIX + "Assume root bridge [%s] bus is 0\n", + (char *)buffer.pointer); + status = AE_OK; + bbn = 0; + } + if (ACPI_FAILURE(status)) { + bbn = -ENODEV; + goto exit; + } + if (bbn > 0) + goto exit; + + /* _BBN in some systems return 0 for all root bridges */ + bus = -1; + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + do_root_bridge_busnr_callback, &bus); + /* If _CRS failed, we just use _BBN */ + if (ACPI_FAILURE(status) || (bus == -1)) + goto exit; + /* We select _CRS */ + if (bbn != bus) { + printk(KERN_INFO PREFIX + "_BBN and _CRS returns different value for %s. Select _CRS\n", + (char *)buffer.pointer); + bbn = bus; + } + exit: + acpi_os_free(buffer.pointer); + return bbn; +} + +static acpi_status +find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context; + unsigned long seg, bus; + acpi_status status; + int tmp; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg); + if (status == AE_NOT_FOUND) { + /* Assume seg = 0 */ + printk(KERN_INFO PREFIX + "Assume root bridge [%s] segment is 0\n", + (char *)buffer.pointer); + status = AE_OK; + seg = 0; + } + if (ACPI_FAILURE(status)) { + status = AE_CTRL_DEPTH; + goto exit; + } + + tmp = get_root_bridge_busnr(handle); + if (tmp < 0) { + printk(KERN_ERR PREFIX + "Find root bridge failed for %s\n", + (char *)buffer.pointer); + status = AE_CTRL_DEPTH; + goto exit; + } + bus = tmp; + + if (seg == find->seg && bus == find->bus) + find->handle = handle; + status = AE_OK; + exit: + acpi_os_free(buffer.pointer); + return status; +} + +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) +{ + struct acpi_find_pci_root find = { seg, bus, NULL }; + + acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); + return find.handle; +} + +/* Get device's handler per its address under its parent */ +struct acpi_find_child { + acpi_handle handle; + acpi_integer address; +}; + +static acpi_status +do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + struct acpi_device_info *info; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_find_child *find = (struct acpi_find_child *)context; + + status = acpi_get_object_info(handle, &buffer); + if (ACPI_SUCCESS(status)) { + info = buffer.pointer; + if (info->address == find->address) + find->handle = handle; + acpi_os_free(buffer.pointer); + } + return AE_OK; +} + +acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) +{ + struct acpi_find_child find = { NULL, address }; + + if (!parent) + return NULL; + acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, + 1, do_acpi_find_child, &find, NULL); + return find.handle; +} + +EXPORT_SYMBOL(acpi_get_child); + +/* Link ACPI devices with physical devices */ +static void acpi_glue_data_handler(acpi_handle handle, + u32 function, void *context) +{ + /* we provide an empty handler */ +} + +/* Note: a success call will increase reference count by one */ +struct device *acpi_get_physical_device(acpi_handle handle) +{ + acpi_status status; + struct device *dev; + + status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); + if (ACPI_SUCCESS(status)) + return get_device(dev); + return NULL; +} + +EXPORT_SYMBOL(acpi_get_physical_device); + +static int acpi_bind_one(struct device *dev, acpi_handle handle) +{ + acpi_status status; + + if (dev->firmware_data) { + printk(KERN_WARNING PREFIX + "Drivers changed 'firmware_data' for %s\n", dev->bus_id); + return -EINVAL; + } + get_device(dev); + status = acpi_attach_data(handle, acpi_glue_data_handler, dev); + if (ACPI_FAILURE(status)) { + put_device(dev); + return -EINVAL; + } + dev->firmware_data = handle; + + return 0; +} + +static int acpi_unbind_one(struct device *dev) +{ + if (!dev->firmware_data) + return 0; + if (dev == acpi_get_physical_device(dev->firmware_data)) { + /* acpi_get_physical_device increase refcnt by one */ + put_device(dev); + acpi_detach_data(dev->firmware_data, acpi_glue_data_handler); + dev->firmware_data = NULL; + /* acpi_bind_one increase refcnt by one */ + put_device(dev); + } else { + printk(KERN_ERR PREFIX + "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id); + } + return 0; +} + +static int acpi_platform_notify(struct device *dev) +{ + struct acpi_bus_type *type; + acpi_handle handle; + int ret = -EINVAL; + + if (!dev->bus || !dev->parent) { + /* bridge devices genernally haven't bus or parent */ + ret = acpi_find_bridge_device(dev, &handle); + goto end; + } + type = acpi_get_bus_type(dev->bus); + if (!type) { + printk(KERN_INFO PREFIX "No ACPI bus support for %s\n", + dev->bus_id); + ret = -EINVAL; + goto end; + } + if ((ret = type->find_device(dev, &handle)) != 0) + printk(KERN_INFO PREFIX "Can't get handler for %s\n", + dev->bus_id); + end: + if (!ret) + acpi_bind_one(dev, handle); + +#if ACPI_GLUE_DEBUG + if (!ret) { + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer); + DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); + acpi_os_free(buffer.pointer); + } else + DBG("Device %s -> No ACPI support\n", dev->bus_id); +#endif + + return ret; +} + +static int acpi_platform_notify_remove(struct device *dev) +{ + acpi_unbind_one(dev); + return 0; +} + +static int __init init_acpi_device_notify(void) +{ + if (acpi_disabled) + return 0; + if (platform_notify || platform_notify_remove) { + printk(KERN_ERR PREFIX "Can't use platform_notify\n"); + return 0; + } + platform_notify = acpi_platform_notify; + platform_notify_remove = acpi_platform_notify_remove; + return 0; +} + +arch_initcall(init_acpi_device_notify); diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 6c8291c3e77..ad85e10001f 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1025,7 +1025,7 @@ static int setup_notify(struct ibm_struct *ibm) return 0; } -static int device_add(struct acpi_device *device) +static int ibmacpi_device_add(struct acpi_device *device) { return 0; } @@ -1043,7 +1043,7 @@ static int register_driver(struct ibm_struct *ibm) memset(ibm->driver, 0, sizeof(struct acpi_driver)); sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); ibm->driver->ids = ibm->hid; - ibm->driver->ops.add = &device_add; + ibm->driver->ops.add = &ibmacpi_device_add; ret = acpi_bus_register_driver(ibm->driver); if (ret < 0) { -- cgit v1.2.3 From 84df749f364209c9623304b7a94ddb954dc343bb Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 18:53:36 -0500 Subject: [ACPI] Bind ACPI and PCI devices http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index bc01d34e263..f94c86fbc66 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,9 +1,10 @@ /* * File: pci-acpi.c - * Purpose: Provide PCI supports in ACPI + * Purpose: Provide PCI support in ACPI * - * Copyright (C) 2004 Intel - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + * Copyright (C) 2005 David Shaohua Li + * Copyright (C) 2004 Tom Long Nguyen + * Copyright (C) 2004 Intel Corp. */ #include @@ -207,3 +208,53 @@ acpi_status pci_osc_control_set(u32 flags) return status; } EXPORT_SYMBOL(pci_osc_control_set); + +/* ACPI bus type */ +static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) +{ + struct pci_dev * pci_dev; + acpi_integer addr; + + pci_dev = to_pci_dev(dev); + /* Please ref to ACPI spec for the syntax of _ADR */ + addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + if (!*handle) + return -ENODEV; + return 0; +} + +static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) +{ + int num; + unsigned int seg, bus; + + /* + * The string should be the same as root bridge's name + * Please look at 'pci_scan_bus_parented' + */ + num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); + if (num != 2) + return -ENODEV; + *handle = acpi_get_pci_rootbridge_handle(seg, bus); + if (!*handle) + return -ENODEV; + return 0; +} + +static struct acpi_bus_type pci_acpi_bus = { + .bus = &pci_bus_type, + .find_device = pci_acpi_find_device, + .find_bridge = pci_acpi_find_root_bridge, +}; + +static int __init pci_acpi_init(void) +{ + int ret; + + ret = register_acpi_bus_type(&pci_acpi_bus); + if (ret) + return 0; + return 0; +} +arch_initcall(pci_acpi_init); -- cgit v1.2.3 From 0f64474b8f7f1f7f3af5b24ef997baa35f923509 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Sat, 19 Mar 2005 00:15:48 -0500 Subject: [ACPI] PCI can now get suspend state from firmware pci_choose_state() can now call platform_pci_choose_state() and ACPI can answer http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.c | 11 ++++++++++- drivers/pci/pci.h | 3 +++ 3 files changed, 59 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index f94c86fbc66..8eb599708de 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,6 +1,6 @@ /* * File: pci-acpi.c - * Purpose: Provide PCI support in ACPI + * Purpose: Provde PCI support in ACPI * * Copyright (C) 2005 David Shaohua Li * Copyright (C) 2004 Tom Long Nguyen @@ -17,6 +17,7 @@ #include #include +#include "pci.h" static u32 ctrlset_buf[3] = {0, 0, 0}; static u32 global_ctrlsets = 0; @@ -209,6 +210,49 @@ acpi_status pci_osc_control_set(u32 flags) } EXPORT_SYMBOL(pci_osc_control_set); +/* + * _SxD returns the D-state with the highest power + * (lowest D-state number) supported in the S-state "x". + * + * If the devices does not have a _PRW + * (Power Resources for Wake) supporting system wakeup from "x" + * then the OS is free to choose a lower power (higher number + * D-state) than the return value from _SxD. + * + * But if _PRW is enabled at S-state "x", the OS + * must not choose a power lower than _SxD -- + * unless the device has an _SxW method specifying + * the lowest power (highest D-state number) the device + * may enter while still able to wake the system. + * + * ie. depending on global OS policy: + * + * if (_PRW at S-state x) + * choose from highest power _SxD to lowest power _SxW + * else // no _PRW at S-state x + * choose highest power _SxD or any lower power + * + * currently we simply return _SxD, if present. + */ + +static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) +{ + char dstate_str[] = "_S0D"; + acpi_status status; + unsigned long val; + struct device *dev = &pdev->dev; + + /* Fixme: the check is wrong after pm_message_t is a struct */ + if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev)) + return -EINVAL; + dstate_str[2] += state; /* _S1D, _S2D, _S3D, _S4D */ + status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str, + NULL, &val); + if (ACPI_SUCCESS(status)) + return val; + return -ENODEV; +} + /* ACPI bus type */ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) { @@ -255,6 +299,7 @@ static int __init pci_acpi_init(void) ret = register_acpi_bus_type(&pci_acpi_bus); if (ret) return 0; + platform_pci_choose_state = acpi_pci_choose_state; return 0; } arch_initcall(pci_acpi_init); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f04b9ffe415..5af94180778 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -304,6 +304,8 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } +int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state) = NULL; + /** * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended @@ -316,10 +318,17 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { + int ret; + if (!pci_find_capability(dev, PCI_CAP_ID_PM)) return PCI_D0; - switch (state) { + if (platform_pci_choose_state) { + ret = platform_pci_choose_state(dev, state); + if (ret >= 0) + state = ret; + } + switch (state) { case 0: return PCI_D0; case 3: return PCI_D3hot; default: diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 744da0d4ae5..25c44922f7d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -11,6 +11,9 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void (*alignf)(void *, struct resource *, unsigned long, unsigned long), void *alignf_data); +/* Firmware callbacks */ +extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); + /* PCI /proc functions */ #ifdef CONFIG_PROC_FS extern int pci_proc_attach_device(struct pci_dev *dev); -- cgit v1.2.3 From b913100d7304ea9596d8d85ab5f3ae04bd2b0ddb Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Sat, 19 Mar 2005 00:16:18 -0500 Subject: [ACPI] pci_set_power_state() now calls platform_pci_set_power_state() and ACPI can answer http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/bus.c | 8 +++++++- drivers/pci/pci-acpi.c | 19 +++++++++++++++++++ drivers/pci/pci.c | 11 +++++++++-- drivers/pci/pci.h | 1 + 4 files changed, 36 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4edff173857..d77c2307883 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -212,6 +212,12 @@ acpi_bus_set_power ( ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n")); return_VALUE(-ENODEV); } + /* + * Get device's current power state if it's unknown + * This means device power state isn't initialized or previous setting failed + */ + if (device->power.state == ACPI_STATE_UNKNOWN) + acpi_bus_get_power(device->handle, &device->power.state); if (state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return_VALUE(0); @@ -231,7 +237,7 @@ acpi_bus_set_power ( * On transitions to a high-powered state we first apply power (via * power resources) then evalute _PSx. Conversly for transitions to * a lower-powered state. - */ + */ if (state < device->power.state) { if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 8eb599708de..a0d43ea872d 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -253,6 +253,24 @@ static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) return -ENODEV; } +static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); + static int state_conv[] = { + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + [4] = 3 + }; + int acpi_state = state_conv[(int __force) state]; + + if (!handle) + return -ENODEV; + return acpi_bus_set_power(handle, acpi_state); +} + + /* ACPI bus type */ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) { @@ -300,6 +318,7 @@ static int __init pci_acpi_init(void) if (ret) return 0; platform_pci_choose_state = acpi_pci_choose_state; + platform_pci_set_power_state = acpi_pci_set_power_state; return 0; } arch_initcall(pci_acpi_init); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5af94180778..a1c66e8ea5f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ - +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t) = NULL; int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -299,8 +299,15 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) msleep(10); else if (state == PCI_D2 || dev->current_state == PCI_D2) udelay(200); - dev->current_state = state; + /* + * Give firmware a chance to be called, such as ACPI _PRx, _PSx + * Firmware method after natice method ? + */ + if (platform_pci_set_power_state) + platform_pci_set_power_state(dev, state); + + dev->current_state = state; return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 25c44922f7d..d94d7af4f7a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -13,6 +13,7 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void *alignf_data); /* Firmware callbacks */ extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); +extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); /* PCI /proc functions */ #ifdef CONFIG_PROC_FS -- cgit v1.2.3 From 451566f45a2e6cd10ba56e7220a9dd84ba3ef550 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 19 Mar 2005 01:10:05 -0500 Subject: [ACPI] Enable EC Burst Mode Fixes several Embedded Controller issues, including button failure and battery status AE_TIME failure. http://bugzilla.kernel.org/show_bug.cgi?id=3851 Based on patch by: Andi Kleen Signed-off-by: Dmitry Torokhov Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 390 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 276 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index fdf143b405b..69b04d430f0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec") #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ +#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ #define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ -#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ +#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_COMMAND_READ 0x80 #define ACPI_EC_COMMAND_WRITE 0x81 +#define ACPI_EC_BURST_ENABLE 0x82 +#define ACPI_EC_BURST_DISABLE 0x83 #define ACPI_EC_COMMAND_QUERY 0x84 static int acpi_ec_add (struct acpi_device *device); @@ -87,7 +90,11 @@ struct acpi_ec { struct acpi_generic_address command_addr; struct acpi_generic_address data_addr; unsigned long global_lock; - spinlock_t lock; + unsigned int expect_event; + atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort*/ + atomic_t pending_gpe; + struct semaphore sem; + wait_queue_head_t wait; }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -100,59 +107,138 @@ static struct acpi_device *first_ec; Transaction Management -------------------------------------------------------------------------- */ -static int -acpi_ec_wait ( - struct acpi_ec *ec, - u8 event) +static inline u32 acpi_ec_read_status(struct acpi_ec *ec) { - u32 acpi_ec_status = 0; - u32 i = ACPI_EC_UDELAY_COUNT; + u32 status = 0; - if (!ec) - return -EINVAL; + acpi_hw_low_level_read(8, &status, &ec->status_addr); + return status; +} + +static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_wait"); - /* Poll the EC status register waiting for the event to occur. */ + ec->expect_event = event; + smp_mb(); + + result = wait_event_interruptible_timeout(ec->wait, + !ec->expect_event, + msecs_to_jiffies(ACPI_EC_DELAY)); + + ec->expect_event = 0; + smp_mb(); + + if (result < 0){ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result)); + return_VALUE(result); + } + + /* + * Verify that the event in question has actually happened by + * querying EC status. Do the check even if operation timed-out + * to make sure that we did not miss interrupt. + */ switch (event) { case ACPI_EC_EVENT_OBF: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); - if (acpi_ec_status & ACPI_EC_FLAG_OBF) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i>0); + if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) + return_VALUE(0); break; + case ACPI_EC_EVENT_IBE: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); - if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i>0); + if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) + return_VALUE(0); break; - default: - return -EINVAL; } - return -ETIME; + return_VALUE(-ETIME); } + +static int +acpi_ec_enter_burst_mode ( + struct acpi_ec *ec) +{ + u32 tmp = 0; + int status = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode"); + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + !(status & ACPI_EC_FLAG_BURST)){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"entering burst mode \n")); + acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR," status = %d\n", status)); + return_VALUE(-EINVAL); + } + acpi_hw_low_level_read(8, &tmp, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if(tmp != 0x90 ) {/* Burst ACK byte*/ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Ack failed \n")); + return_VALUE(-EINVAL); + } + } else + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in burst mode \n")); + atomic_set(&ec->leaving_burst , 0); + return_VALUE(0); +} + +static int +acpi_ec_leave_burst_mode ( + struct acpi_ec *ec) +{ + int status =0; + + ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode"); + + atomic_set(&ec->leaving_burst , 1); + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + (status & ACPI_EC_FLAG_BURST)){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); + acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n")); + return_VALUE(-EINVAL); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + (status & ACPI_EC_FLAG_BURST)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->status fail\n")); + return_VALUE(-EINVAL); + } + }else + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in Non-burst mode \n")); + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); + + return_VALUE(0); +} + static int acpi_ec_read ( struct acpi_ec *ec, u8 address, u32 *data) { - acpi_status status = AE_OK; - int result = 0; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; ACPI_FUNCTION_TRACE("acpi_ec_read"); if (!ec || !data) return_VALUE(-EINVAL); +retry: *data = 0; if (ec->global_lock) { @@ -160,32 +246,50 @@ acpi_ec_read ( if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); } - - spin_lock_irqsave(&ec->lock, flags); + + WARN_ON(in_interrupt()); + down(&ec->sem); + + if(acpi_ec_enter_burst_mode(ec)) + goto end; acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status) { goto end; + } acpi_hw_low_level_write(8, address, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) + status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; - + } acpi_hw_low_level_read(8, data, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", *data, address)); - + end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } @@ -195,49 +299,80 @@ acpi_ec_write ( u8 address, u8 data) { - int result = 0; - acpi_status status = AE_OK; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; + u32 tmp; ACPI_FUNCTION_TRACE("acpi_ec_write"); if (!ec) return_VALUE(-EINVAL); - +retry: if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); } - spin_lock_irqsave(&ec->lock, flags); + WARN_ON(in_interrupt()); + down(&ec->sem); + + if(acpi_ec_enter_burst_mode(ec)) + goto end; + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + !(status & ACPI_EC_FLAG_BURST)){ + acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status) + goto end; + acpi_hw_low_level_read(8, &tmp, &ec->data_addr); + if(tmp != 0x90 ) /* Burst ACK byte*/ + goto end; + } + /*Now we are in burst mode*/ acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status){ goto end; + } acpi_hw_low_level_write(8, address, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; + } acpi_hw_low_level_write(8, data, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status) goto end; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", data, address)); end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } /* @@ -289,16 +424,14 @@ acpi_ec_query ( struct acpi_ec *ec, u32 *data) { - int result = 0; - acpi_status status = AE_OK; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; ACPI_FUNCTION_TRACE("acpi_ec_query"); if (!ec || !data) return_VALUE(-EINVAL); - +retry: *data = 0; if (ec->global_lock) { @@ -307,29 +440,43 @@ acpi_ec_query ( return_VALUE(-ENODEV); } + down(&ec->sem); + if(acpi_ec_enter_burst_mode(ec)) + goto end; /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - spin_lock_irqsave(&ec->lock, flags); - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; - + } + acpi_hw_low_level_read(8, data, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); if (!*data) - result = -ENODATA; + status = -ENODATA; end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } @@ -347,42 +494,29 @@ acpi_ec_gpe_query ( void *ec_cxt) { struct acpi_ec *ec = (struct acpi_ec *) ec_cxt; - u32 value = 0; - unsigned long flags = 0; + u32 value; + int result = -ENODATA; static char object_name[5] = {'_','Q','0','0','\0'}; const char hex[] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); - if (!ec_cxt) - goto end; + if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) + result = acpi_ec_query(ec, &value); - spin_lock_irqsave(&ec->lock, flags); - acpi_hw_low_level_read(8, &value, &ec->command_addr); - spin_unlock_irqrestore(&ec->lock, flags); - - /* TBD: Implement asynch events! - * NOTE: All we care about are EC-SCI's. Other EC events are - * handled via polling (yuck!). This is because some systems - * treat EC-SCIs as level (versus EDGE!) triggered, preventing - * a purely interrupt-driven approach (grumble, grumble). - */ - if (!(value & ACPI_EC_FLAG_SCI)) + if (result) goto end; - if (acpi_ec_query(ec, &value)) - goto end; - object_name[2] = hex[((value >> 4) & 0x0F)]; object_name[3] = hex[(value & 0x0F)]; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - -end: - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + atomic_dec(&ec->pending_gpe); +end: + return; } static u32 @@ -390,6 +524,7 @@ acpi_ec_gpe_handler ( void *data) { acpi_status status = AE_OK; + u32 value; struct acpi_ec *ec = (struct acpi_ec *) data; if (!ec) @@ -397,13 +532,39 @@ acpi_ec_gpe_handler ( acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); - status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, - acpi_ec_gpe_query, ec); + value = acpi_ec_read_status(ec); - if (status == AE_OK) - return ACPI_INTERRUPT_HANDLED; - else - return ACPI_INTERRUPT_NOT_HANDLED; + if((value & ACPI_EC_FLAG_IBF) && + !(value & ACPI_EC_FLAG_BURST) && + (atomic_read(&ec->leaving_burst) == 0)) { + /* + * the embedded controller disables + * burst mode for any reason other + * than the burst disable command + * to process critical event. + */ + atomic_set(&ec->leaving_burst , 2); /* block current pending transaction + and retry */ + wake_up(&ec->wait); + }else { + if ((ec->expect_event == ACPI_EC_EVENT_OBF && + (value & ACPI_EC_FLAG_OBF)) || + (ec->expect_event == ACPI_EC_EVENT_IBE && + !(value & ACPI_EC_FLAG_IBF))) { + ec->expect_event = 0; + wake_up(&ec->wait); + + } + } + + if (value & ACPI_EC_FLAG_SCI){ + atomic_add(1, &ec->pending_gpe) ; + status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + acpi_ec_gpe_query, ec); + } + + return status == AE_OK ? + ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } /* -------------------------------------------------------------------------- @@ -421,10 +582,8 @@ acpi_ec_space_setup ( * The EC object is in the handler context and is needed * when calling the acpi_ec_space_handler. */ - if(function == ACPI_REGION_DEACTIVATE) - *return_context = NULL; - else - *return_context = handler_context; + *return_context = (function != ACPI_REGION_DEACTIVATE) ? + handler_context : NULL; return AE_OK; } @@ -555,7 +714,7 @@ static int acpi_ec_add_fs ( struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; + struct proc_dir_entry *entry; ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); @@ -606,9 +765,9 @@ static int acpi_ec_add ( struct acpi_device *device) { - int result = 0; - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + int result; + acpi_status status; + struct acpi_ec *ec; unsigned long uid; ACPI_FUNCTION_TRACE("acpi_ec_add"); @@ -623,7 +782,10 @@ acpi_ec_add ( ec->handle = device->handle; ec->uid = -1; - spin_lock_init(&ec->lock); + atomic_set(&ec->pending_gpe, 0); + atomic_set(&ec->leaving_burst , 1); + init_MUTEX(&ec->sem); + init_waitqueue_head(&ec->wait); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; @@ -637,7 +799,7 @@ acpi_ec_add ( if (ec_ecdt && ec_ecdt->uid == uid) { acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); kfree(ec_ecdt); @@ -677,7 +839,7 @@ acpi_ec_remove ( struct acpi_device *device, int type) { - struct acpi_ec *ec = NULL; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_remove"); @@ -732,8 +894,8 @@ static int acpi_ec_start ( struct acpi_device *device) { - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + acpi_status status; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_start"); @@ -789,8 +951,8 @@ acpi_ec_stop ( struct acpi_device *device, int type) { - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + acpi_status status; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_stop"); @@ -832,7 +994,6 @@ acpi_fake_ecdt_callback ( status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit); if (ACPI_FAILURE(status)) return status; - spin_lock_init(&ec_ecdt->lock); ec_ecdt->global_lock = TRUE; ec_ecdt->handle = handle; @@ -890,7 +1051,7 @@ acpi_ec_get_real_ecdt(void) acpi_status status; struct acpi_table_ecdt *ecdt_ptr; - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, + status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, (struct acpi_table_header **) &ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; @@ -905,11 +1066,12 @@ acpi_ec_get_real_ecdt(void) return -ENOMEM; memset(ec_ecdt, 0, sizeof(struct acpi_ec)); + init_MUTEX(&ec_ecdt->sem); + init_waitqueue_head(&ec_ecdt->wait); ec_ecdt->command_addr = ecdt_ptr->ec_control; ec_ecdt->status_addr = ecdt_ptr->ec_control; ec_ecdt->data_addr = ecdt_ptr->ec_data; ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; - spin_lock_init(&ec_ecdt->lock); /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; ec_ecdt->uid = ecdt_ptr->uid; @@ -978,7 +1140,7 @@ error: static int __init acpi_ec_init (void) { - int result = 0; + int result; ACPI_FUNCTION_TRACE("acpi_ec_init"); -- cgit v1.2.3 From fa9cd547e097df4966b8bd5c94aeed953e32b14d Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Sat, 19 Mar 2005 01:54:47 -0500 Subject: [ACPI] fix EC access width http://bugzilla.kernel.org/show_bug.cgi?id=4346 Written-by: David Shaohua Li and Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 69b04d430f0..e3716222934 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -600,7 +600,7 @@ acpi_ec_space_handler ( { int result = 0; struct acpi_ec *ec = NULL; - u32 temp = 0; + u64 temp = *value; acpi_integer f_v = 0; int i = 0; @@ -609,10 +609,9 @@ acpi_ec_space_handler ( if ((address > 0xFF) || !value || !handler_context) return_VALUE(AE_BAD_PARAMETER); - if(bit_width != 8) { + if (bit_width != 8 && acpi_strict) { printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n"); - if (acpi_strict) - return_VALUE(AE_BAD_PARAMETER); + return_VALUE(AE_BAD_PARAMETER); } ec = (struct acpi_ec *) handler_context; @@ -620,11 +619,11 @@ acpi_ec_space_handler ( next_byte: switch (function) { case ACPI_READ: - result = acpi_ec_read(ec, (u8) address, &temp); - *value = (acpi_integer) temp; + temp = 0; + result = acpi_ec_read(ec, (u8) address, (u32 *)&temp); break; case ACPI_WRITE: - result = acpi_ec_write(ec, (u8) address, (u8) *value); + result = acpi_ec_write(ec, (u8) address, (u8) temp); break; default: result = -EINVAL; @@ -633,19 +632,18 @@ next_byte: } bit_width -= 8; - if(bit_width){ - - if(function == ACPI_READ) - f_v |= (acpi_integer) (*value) << 8*i; - if(function == ACPI_WRITE) - (*value) >>=8; + if (bit_width) { + if (function == ACPI_READ) + f_v |= temp << 8 * i; + if (function == ACPI_WRITE) + temp >>= 8; i++; + (u8)address ++; goto next_byte; } - - if(function == ACPI_READ){ - f_v |= (acpi_integer) (*value) << 8*i; + if (function == ACPI_READ) { + f_v |= temp << 8 * i; *value = f_v; } @@ -664,8 +662,6 @@ out: default: return_VALUE(AE_OK); } - - } -- cgit v1.2.3 From a406d9e63e1d7088aad22565449de2e109300e5c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 23 Mar 2005 16:16:03 -0500 Subject: [ACPI] gut acpi_pci_choose_state() to avoid conflict with pending pm_message_t re-definition. Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a0d43ea872d..e9e37abe1f7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,6 +1,6 @@ /* * File: pci-acpi.c - * Purpose: Provde PCI support in ACPI + * Purpose: Provide PCI support in ACPI * * Copyright (C) 2005 David Shaohua Li * Copyright (C) 2004 Tom Long Nguyen @@ -237,19 +237,8 @@ EXPORT_SYMBOL(pci_osc_control_set); static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) { - char dstate_str[] = "_S0D"; - acpi_status status; - unsigned long val; - struct device *dev = &pdev->dev; + /* TBD */ - /* Fixme: the check is wrong after pm_message_t is a struct */ - if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev)) - return -EINVAL; - dstate_str[2] += state; /* _S1D, _S2D, _S3D, _S4D */ - status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str, - NULL, &val); - if (ACPI_SUCCESS(status)) - return val; return -ENODEV; } -- cgit v1.2.3 From b008b8d7092053fc1f036cfc54dc11740cc424ed Mon Sep 17 00:00:00 2001 From: Matthieu Castet Date: Fri, 25 Mar 2005 12:03:15 -0500 Subject: [ACPI] PNPACPI parse error http://bugzilla.kernel.org/show_bug.cgi?id=3912 Written-by: matthieu castet Acked-by: Shaohua Li Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index dd61e09029b..ae3819ad7cf 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -444,6 +444,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, struct acpipnp_parse_option_s { struct pnp_option *option; + struct pnp_option *option_independent; struct pnp_dev *dev; }; @@ -507,7 +508,14 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res, parse_data->option = option; break; case ACPI_RSTYPE_END_DPF: - return AE_CTRL_TERMINATE; + /*only one EndDependentFn is allowed*/ + if (!parse_data->option_independent) { + pnp_warn("PnPACPI: more than one EndDependentFn"); + return AE_ERROR; + } + parse_data->option = parse_data->option_independent; + parse_data->option_independent = NULL; + break; default: pnp_warn("PnPACPI: unknown resource type %d", res->id); return AE_ERROR; @@ -525,6 +533,7 @@ acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle, parse_data.option = pnp_register_independent_option(dev); if (!parse_data.option) return AE_ERROR; + parse_data.option_independent = parse_data.option; parse_data.dev = dev; status = acpi_walk_resources(handle, METHOD_NAME__PRS, pnpacpi_option_resource, &parse_data); -- cgit v1.2.3 From f165b10f4a9aac7fee9b11a125de20a1712be128 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 30 Mar 2005 21:23:19 -0500 Subject: cleanup: remove unnecessary initializer on static pointers Suggested-by: Greg KH Signed-off-by: Len Brown --- drivers/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a1c66e8ea5f..bdfca32b44a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ -int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t) = NULL; +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -311,7 +311,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } -int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state) = NULL; +int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); /** * pci_choose_state - Choose the power state of a PCI device -- cgit v1.2.3 From 83ea7445221651dc43cf8d22f81089e0cbccf22b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Mar 2005 22:12:13 -0500 Subject: [ACPI] fix build warning Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e3716222934..a4b70dfdcf0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -638,7 +638,7 @@ next_byte: if (function == ACPI_WRITE) temp >>= 8; i++; - (u8)address ++; + address++; goto next_byte; } -- cgit v1.2.3 From f4224153098c1103db592b28f304beeb9c02481b Mon Sep 17 00:00:00 2001 From: Panagiotis Issaris Date: Wed, 30 Mar 2005 22:15:36 -0500 Subject: [ACPI] check for kmalloc failure in toshiba_acpi.c Signed-off-by: Panagiotis Issaris Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/toshiba_acpi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index bed8e53a5ee..73b1d8aeae9 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -263,6 +263,9 @@ dispatch_write(struct file* file, const char __user * buffer, * destination so that sscanf can be used on it safely. */ tmp_buffer = kmalloc(count + 1, GFP_KERNEL); + if(!tmp_buffer) + return -ENOMEM; + if (copy_from_user(tmp_buffer, buffer, count)) { result = -EFAULT; } -- cgit v1.2.3 From 7334571f724df7a19f48cc974e991e00afde1e2f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 30 Mar 2005 22:31:35 -0500 Subject: [ACPI] fix potential NULL dereference in acpi/video.c Found-by: Adrian Bunk Signed-off-by: Len Brown --- drivers/acpi/video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 71fa1011715..b3b352b8330 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1585,7 +1585,7 @@ acpi_video_switch_output( ACPI_FUNCTION_TRACE("acpi_video_switch_output"); list_for_each_safe(node, next, &video->video_device_list) { - struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry); + dev = container_of(node, struct acpi_video_device, entry); status = acpi_video_device_get_state(dev, &state); if (state & 0x2){ dev_next = container_of(node->next, struct acpi_video_device, entry); -- cgit v1.2.3 From d1dd0c23916bd781de27bc5ec1c295064e9ce9cc Mon Sep 17 00:00:00 2001 From: Paulo Marques Date: Wed, 30 Mar 2005 22:39:49 -0500 Subject: [ACPI] fix kmalloc size bug in acpi/video.c acpi_video_device_find_cap() used &p instead of *p when calculating storage size, thus allocating only 4 or 8 bytes instead of 12... Also, kfree(NULL) is legal, so remove some unneeded checks. From: Paulo Marques Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/video.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b3b352b8330..2cf264fd52e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -564,12 +564,13 @@ acpi_video_device_find_cap (struct acpi_video_device *device) int count = 0; union acpi_object *o; - br = kmalloc(sizeof &br, GFP_KERNEL); + br = kmalloc(sizeof(*br), GFP_KERNEL); if (!br) { printk(KERN_ERR "can't allocate memory\n"); } else { - memset(br, 0, sizeof &br); - br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL); + memset(br, 0, sizeof(*br)); + br->levels = kmalloc(obj->package.count * + sizeof *(br->levels), GFP_KERNEL); if (!br->levels) goto out; @@ -584,8 +585,7 @@ acpi_video_device_find_cap (struct acpi_video_device *device) } out: if (count < 2) { - if (br->levels) - kfree(br->levels); + kfree(br->levels); kfree(br); } else { br->count = count; @@ -595,8 +595,7 @@ out: } } - if (obj) - kfree(obj); + kfree(obj); return_VOID; } -- cgit v1.2.3 From 8de7a63b69a263b7549599be882d7aa15397f8b3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Mar 2005 22:53:30 -0500 Subject: [ACPI] fix debug-mode build warning in acpi/hotkey.c drivers/acpi/hotkey.c: In function `create_polling_proc': drivers/acpi/hotkey.c:334: warning: ISO C90 forbids mixed declarations and code Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/hotkey.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index 0aef9fc449c..babdf762ead 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -329,9 +329,10 @@ static int auto_hotkey_remove(struct acpi_device *device, int type) static int create_polling_proc(union acpi_hotkey *device) { struct proc_dir_entry *proc; + mode_t mode; ACPI_FUNCTION_TRACE("create_polling_proc"); - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + mode = S_IFREG | S_IRUGO | S_IWUGO; proc = create_proc_entry(device->poll_hotkey.action_method, mode, hotkey_proc_dir); -- cgit v1.2.3 From 6940fabaa35b893163b7043d0d1dc5d715f9e1ca Mon Sep 17 00:00:00 2001 From: Keiichiro Tokunaga Date: Wed, 30 Mar 2005 23:15:47 -0500 Subject: [ACPI] hotplug Processor consideration in acpi_bus_add() Signed-off-by: Keiichiro Tokunaga Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 119c94093a1..7c26fed0bdf 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1051,13 +1051,15 @@ acpi_bus_add ( /* * Status * ------ - * See if the device is present. We always assume that non-Device() - * objects (e.g. thermal zones, power resources, processors, etc.) are - * present, functioning, etc. (at least when parent object is present). - * Note that _STA has a different meaning for some objects (e.g. - * power resources) so we need to be careful how we use it. + * See if the device is present. We always assume that non-Device + * and non-Processor objects (e.g. thermal zones, power resources, + * etc.) are present, functioning, etc. (at least when parent object + * is present). Note that _STA has a different meaning for some + * objects (e.g. power resources) so we need to be careful how we use + * it. */ switch (type) { + case ACPI_BUS_TYPE_PROCESSOR: case ACPI_BUS_TYPE_DEVICE: result = acpi_bus_get_status(device); if (ACPI_FAILURE(result) || !device->status.present) { -- cgit v1.2.3 From acf05f4b7f558051ea0028e8e617144123650272 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Thu, 31 Mar 2005 23:23:15 -0500 Subject: [ACPI] update /proc/acpi/processor/*/power even if only C1 support Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ff64d333e95..79d5ca3066c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -519,6 +519,29 @@ static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr) } +static int acpi_processor_get_power_info_default_c1 (struct acpi_processor *pr) +{ + int i; + + ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1"); + + for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) + memset(pr->power.states, 0, sizeof(struct acpi_processor_cx)); + + /* if info is obtained from pblk/fadt, type equals state */ + pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; + pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; + pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; + + /* the C0 state only exists as a filler in our array, + * and all processors need to support C1 */ + pr->power.states[ACPI_STATE_C0].valid = 1; + pr->power.states[ACPI_STATE_C1].valid = 1; + + return_VALUE(0); +} + + static int acpi_processor_get_power_info_cst (struct acpi_processor *pr) { acpi_status status = 0; @@ -787,10 +810,7 @@ static int acpi_processor_get_power_info ( if ((result) || (acpi_processor_power_verify(pr) < 2)) { result = acpi_processor_get_power_info_fadt(pr); if (result) - return_VALUE(result); - - if (acpi_processor_power_verify(pr) < 2) - return_VALUE(-ENODEV); + result = acpi_processor_get_power_info_default_c1(pr); } /* @@ -810,11 +830,10 @@ static int acpi_processor_get_power_info ( * CPU as being "idle manageable" */ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { - if (pr->power.states[i].valid) + if (pr->power.states[i].valid) { pr->power.count = i; - if ((pr->power.states[i].valid) && - (pr->power.states[i].type >= ACPI_STATE_C2)) pr->flags.power = 1; + } } return_VALUE(0); -- cgit v1.2.3 From c9c3e457de24cca2ca688fa397d93a241f472048 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 1 Apr 2005 00:07:31 -0500 Subject: [ACPI] PNPACPI vs sound IRQ http://bugme.osdl.org/show_bug.cgi?id=4016 Written-by: David Shaohua Li Acked-by: Adam Belay Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 7 +++++-- drivers/pnp/pnpacpi/rsparser.c | 4 ++-- drivers/pnp/pnpbios/rsparser.c | 2 +- drivers/pnp/resource.c | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index f2271173bbd..6ad0e77df9b 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -804,9 +804,12 @@ static int __init acpi_irq_penalty_update(char *str, int used) * There is no ISA_POSSIBLE weight, so we simply use * the (small) PCI_USING penalty. */ -void acpi_penalize_isa_irq(int irq) +void acpi_penalize_isa_irq(int irq, int active) { - acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + if (active) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + else + acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; } /* diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ae3819ad7cf..75575f6c349 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -160,7 +160,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, acpi_register_gsi(res->data.irq.interrupts[0], res->data.irq.edge_level, res->data.irq.active_high_low)); - pcibios_penalize_isa_irq(res->data.irq.interrupts[0]); + pcibios_penalize_isa_irq(res->data.irq.interrupts[0], 1); } break; @@ -171,7 +171,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, acpi_register_gsi(res->data.extended_irq.interrupts[0], res->data.extended_irq.edge_level, res->data.extended_irq.active_high_low)); - pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]); + pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0], 1); } break; case ACPI_RSTYPE_DMA: diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index 79bce7b7574..9001b6f0204 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -64,7 +64,7 @@ pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq) } res->irq_resource[i].start = res->irq_resource[i].end = (unsigned long) irq; - pcibios_penalize_isa_irq(irq); + pcibios_penalize_isa_irq(irq, 1); } } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 2d1322dd7e1..887ad893934 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -102,7 +102,7 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) for (i = 0; i < 16; i++) if (test_bit(i, data->map)) - pcibios_penalize_isa_irq(i); + pcibios_penalize_isa_irq(i, 0); } #endif return 0; -- cgit v1.2.3 From d5950b4355049092739bea97d1bdc14433126cc5 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 11 Jul 2005 21:03:49 -0700 Subject: [NET]: add a top-level Networking menu to *config Create a new top-level menu named "Networking" thus moving net related options and protocol selection way from the drivers menu and up on the top-level where they belong. To implement this all architectures has to source "net/Kconfig" before drivers/*/Kconfig in their Kconfig file. This change has been implemented for all architectures. Device drivers for ordinary NIC's are still to be found in the Device Drivers section, but Bluetooth, IrDA and ax25 are located with their corresponding menu entries under the new networking menu item. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/Kconfig | 2 +- drivers/net/Kconfig | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index aed4a9b97c1..34efb2150e6 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -28,7 +28,7 @@ source "drivers/message/i2o/Kconfig" source "drivers/macintosh/Kconfig" -source "net/Kconfig" +source "drivers/net/Kconfig" source "drivers/isdn/Kconfig" diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2b55687f6ee..9a07ff7a777 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3,6 +3,8 @@ # Network device configuration # +menu "Network device support" + config NETDEVICES depends on NET bool "Network device support" @@ -2547,3 +2549,4 @@ config NETCONSOLE If you want to log kernel messages over the network, enable this. See for details. +endmenu -- cgit v1.2.3 From ebb6e1a6122fd6b7c96470cfd4ce0f04150e5084 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 14 Apr 2005 23:12:56 -0400 Subject: [ACPI] Deprecate /proc/acpi/sleep in favor of /sys/power/state Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 8 ++++++++ drivers/acpi/sleep/proc.c | 9 +++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fa7f4345189..8b6de146255 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -80,6 +80,14 @@ config ACPI_SLEEP_PROC_FS depends on ACPI_SLEEP && PROC_FS default y +config ACPI_SLEEP_PROC_SLEEP + bool "/proc/acpi/sleep (deprecated)" + depends on ACPI_SLEEP_PROC_FS + default n + ---help--- + Create /proc/acpi/sleep + Deprecated by /sys/power/state + config ACPI_AC tristate "AC Adapter" depends on X86 diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index fd7c5a0649a..1be99f0996d 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -13,13 +13,17 @@ #include "sleep.h" +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP #define ACPI_SYSTEM_FILE_SLEEP "sleep" +#endif + #define ACPI_SYSTEM_FILE_ALARM "alarm" #define ACPI_SYSTEM_FILE_WAKEUP_DEVICE "wakeup" #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME ("sleep") +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { @@ -78,6 +82,7 @@ acpi_system_write_sleep ( Done: return error ? error : count; } +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { @@ -452,6 +457,7 @@ static struct file_operations acpi_system_wakeup_device_fops = { .release = single_release, }; +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, .read = seq_read, @@ -459,6 +465,7 @@ static struct file_operations acpi_system_sleep_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, @@ -484,11 +491,13 @@ static int acpi_sleep_proc_init(void) if (acpi_disabled) return 0; +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP /* 'sleep' [R/W]*/ entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_sleep_fops; +#endif /* 'alarm' [R/W] */ entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, -- cgit v1.2.3 From 44f6c01242da4e162f28d8e1216a8c7a91174605 Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Mon, 18 Apr 2005 22:49:35 -0400 Subject: ACPICA 20050408 from Bob Moore Fixed three cases in the interpreter where an "index" argument to an ASL function was still (internally) 32 bits instead of the required 64 bits. This was the Index argument to the Index, Mid, and Match operators. The "strupr" function is now permanently local (acpi_ut_strupr), since this is not a POSIX-defined function and not present in most kernel-level C libraries. References to the C library strupr function have been removed from the headers. Completed the deployment of static functions/prototypes. All prototypes with the static attribute have been moved from the headers to the owning C file. ACPICA 20050329 from Bob Moore An error is now generated if an attempt is made to create a Buffer Field of length zero (A CreateField with a length operand of zero.) The interpreter now issues a warning whenever executable code at the module level is detected during ACPI table load. This will give some idea of the prevalence of this type of code. Implemented support for references to named objects (other than control methods) within package objects. Enhanced package object output for the debug object. Package objects are now completely dumped, showing all elements. Enhanced miscellaneous object output for the debug object. Any object can now be written to the debug object (for example, a device object can be written, and the type of the object will be displayed.) The "static" qualifier has been added to all local functions across the core subsystem. The number of "long" lines (> 80 chars) within the source has been significantly reduced, by about 1/3. Cleaned up all header files to ensure that all CA/iASL functions are prototyped (even static functions) and the formatting is consistent. Two new header files have been added, acopcode.h and acnames.h. Removed several obsolete functions that were no longer used. Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsfield.c | 58 +++-- drivers/acpi/dispatcher/dsinit.c | 28 ++- drivers/acpi/dispatcher/dsmethod.c | 11 +- drivers/acpi/dispatcher/dsmthdat.c | 195 ++++++++------- drivers/acpi/dispatcher/dsobject.c | 79 +++--- drivers/acpi/dispatcher/dsopcode.c | 105 +++++--- drivers/acpi/dispatcher/dsutils.c | 41 ++-- drivers/acpi/dispatcher/dswexec.c | 57 +++-- drivers/acpi/dispatcher/dswload.c | 118 +++++---- drivers/acpi/dispatcher/dswscope.c | 31 ++- drivers/acpi/dispatcher/dswstate.c | 458 ++++++++++++++++++----------------- drivers/acpi/events/evevent.c | 33 ++- drivers/acpi/events/evgpe.c | 39 ++- drivers/acpi/events/evgpeblk.c | 63 ++++- drivers/acpi/events/evmisc.c | 97 +++++--- drivers/acpi/events/evregion.c | 35 ++- drivers/acpi/events/evrgnini.c | 14 +- drivers/acpi/events/evsci.c | 12 +- drivers/acpi/events/evxface.c | 19 +- drivers/acpi/events/evxfevnt.c | 25 +- drivers/acpi/executer/exconfig.c | 31 ++- drivers/acpi/executer/exconvrt.c | 44 ++-- drivers/acpi/executer/excreate.c | 50 ++-- drivers/acpi/executer/exdump.c | 105 +++++--- drivers/acpi/executer/exfield.c | 25 +- drivers/acpi/executer/exfldio.c | 133 ++++++---- drivers/acpi/executer/exmisc.c | 7 +- drivers/acpi/executer/exmutex.c | 45 ++-- drivers/acpi/executer/exnames.c | 70 ++++-- drivers/acpi/executer/exoparg1.c | 94 +++++--- drivers/acpi/executer/exoparg2.c | 69 +++--- drivers/acpi/executer/exoparg3.c | 25 +- drivers/acpi/executer/exoparg6.c | 26 +- drivers/acpi/executer/exprep.c | 104 +++++--- drivers/acpi/executer/exregion.c | 34 ++- drivers/acpi/executer/exresnte.c | 24 +- drivers/acpi/executer/exresolv.c | 63 +++-- drivers/acpi/executer/exresop.c | 80 ++++--- drivers/acpi/executer/exstore.c | 260 ++++++++++++++------ drivers/acpi/executer/exstoren.c | 20 +- drivers/acpi/executer/exstorob.c | 9 +- drivers/acpi/executer/exsystem.c | 48 ++-- drivers/acpi/executer/exutils.c | 37 ++- drivers/acpi/hardware/hwacpi.c | 19 +- drivers/acpi/hardware/hwgpe.c | 31 ++- drivers/acpi/hardware/hwregs.c | 114 +++++---- drivers/acpi/hardware/hwsleep.c | 101 ++++---- drivers/acpi/hardware/hwtimer.c | 4 +- drivers/acpi/namespace/nsaccess.c | 5 +- drivers/acpi/namespace/nsalloc.c | 121 +++++----- drivers/acpi/namespace/nsdump.c | 109 +++++---- drivers/acpi/namespace/nsdumpdv.c | 18 +- drivers/acpi/namespace/nseval.c | 70 ++++-- drivers/acpi/namespace/nsinit.c | 28 ++- drivers/acpi/namespace/nsload.c | 28 ++- drivers/acpi/namespace/nsnames.c | 12 +- drivers/acpi/namespace/nsobject.c | 14 +- drivers/acpi/namespace/nssearch.c | 29 ++- drivers/acpi/namespace/nsutils.c | 167 +++++++------ drivers/acpi/namespace/nswalk.c | 2 +- drivers/acpi/namespace/nsxfeval.c | 16 +- drivers/acpi/namespace/nsxfname.c | 8 +- drivers/acpi/namespace/nsxfobj.c | 4 +- drivers/acpi/parser/psargs.c | 55 +++-- drivers/acpi/parser/psopcode.c | 298 +---------------------- drivers/acpi/parser/psparse.c | 144 +++++++---- drivers/acpi/parser/psscope.c | 45 ++-- drivers/acpi/parser/pstree.c | 159 ++++++------ drivers/acpi/parser/psutils.c | 15 +- drivers/acpi/parser/pswalk.c | 11 +- drivers/acpi/parser/psxface.c | 21 +- drivers/acpi/resources/rsaddr.c | 480 ++++++++++++++++--------------------- drivers/acpi/resources/rscalc.c | 144 ++++++----- drivers/acpi/resources/rscreate.c | 45 ++-- drivers/acpi/resources/rsdump.c | 402 ++++++++++++++++--------------- drivers/acpi/resources/rsio.c | 197 +++++++-------- drivers/acpi/resources/rsirq.c | 167 ++++++------- drivers/acpi/resources/rslist.c | 68 +++--- drivers/acpi/resources/rsmemory.c | 236 ++++++++---------- drivers/acpi/resources/rsmisc.c | 160 +++++-------- drivers/acpi/resources/rsutils.c | 53 ++-- drivers/acpi/resources/rsxface.c | 43 ++-- drivers/acpi/tables/tbconvrt.c | 105 +++++--- drivers/acpi/tables/tbget.c | 63 +++-- drivers/acpi/tables/tbgetall.c | 45 ++-- drivers/acpi/tables/tbinstal.c | 31 ++- drivers/acpi/tables/tbrsdt.c | 19 +- drivers/acpi/tables/tbutils.c | 97 ++++---- drivers/acpi/tables/tbxface.c | 39 ++- drivers/acpi/tables/tbxfroot.c | 123 ++++++---- drivers/acpi/utilities/utalloc.c | 84 +++++-- drivers/acpi/utilities/utcopy.c | 126 +++++++--- drivers/acpi/utilities/utdebug.c | 106 ++++---- drivers/acpi/utilities/utdelete.c | 63 +++-- drivers/acpi/utilities/uteval.c | 36 ++- drivers/acpi/utilities/utglobal.c | 133 +++++----- drivers/acpi/utilities/utinit.c | 36 ++- drivers/acpi/utilities/utmath.c | 2 + drivers/acpi/utilities/utmisc.c | 187 ++++++++------- drivers/acpi/utilities/utobject.c | 68 ++++-- drivers/acpi/utilities/utxface.c | 61 +++-- 101 files changed, 4390 insertions(+), 3598 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index 2779211be75..84193983d6b 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -53,13 +53,20 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsfield") +/* Local prototypes */ + +static acpi_status +acpi_ds_get_field_names ( + struct acpi_create_field_info *info, + struct acpi_walk_state *walk_state, + union acpi_parse_object *arg); + /******************************************************************************* * * FUNCTION: acpi_ds_create_buffer_field * - * PARAMETERS: Opcode - The opcode to be executed - * Operands - List of operands for the opcode + * PARAMETERS: Op - Current parse op (create_xXField) * walk_state - Current state * * RETURN: Status @@ -70,7 +77,7 @@ * create_word_field_op, * create_dword_field_op, * create_qword_field_op, - * create_field_op (all of which define fields in buffers) + * create_field_op (all of which define a field in a buffer) * ******************************************************************************/ @@ -119,7 +126,8 @@ acpi_ds_create_buffer_field ( flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; } else { - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; } /* @@ -134,16 +142,16 @@ acpi_ds_create_buffer_field ( } } - /* We could put the returned object (Node) on the object stack for later, but - * for now, we will put it in the "op" object that the parser uses, so we - * can get it again at the end of this scope + /* We could put the returned object (Node) on the object stack for later, + * but for now, we will put it in the "op" object that the parser uses, + * so we can get it again at the end of this scope */ op->common.node = node; /* - * If there is no object attached to the node, this node was just created and - * we need to create the field object. Otherwise, this was a lookup of an - * existing node and we don't want to create the field object again. + * If there is no object attached to the node, this node was just created + * and we need to create the field object. Otherwise, this was a lookup + * of an existing node and we don't want to create the field object again. */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { @@ -205,7 +213,7 @@ cleanup: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_get_field_names ( struct acpi_create_field_info *info, struct acpi_walk_state *walk_state, @@ -238,7 +246,8 @@ acpi_ds_get_field_names ( + (acpi_integer) arg->common.value.size; if (position > ACPI_UINT32_MAX) { - ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n")); + ACPI_REPORT_ERROR (( + "Bit offset within field too large (> 0xFFFFFFFF)\n")); return_ACPI_STATUS (AE_SUPPORT); } @@ -250,12 +259,15 @@ acpi_ds_get_field_names ( /* * Get a new access_type and access_attribute -- to be used for all - * field units that follow, until field end or another access_as keyword. + * field units that follow, until field end or another access_as + * keyword. * - * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits + * In field_flags, preserve the flag bits other than the + * ACCESS_TYPE bits */ - info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | - ((u8) ((u32) arg->common.value.integer >> 8))); + info->field_flags = (u8) + ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | + ((u8) ((u32) arg->common.value.integer >> 8))); info->attribute = (u8) (arg->common.value.integer); break; @@ -267,7 +279,8 @@ acpi_ds_get_field_names ( status = acpi_ns_lookup (walk_state->scope_info, (char *) &arg->named.name, - info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + info->field_type, ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, walk_state, &info->field_node); if (ACPI_FAILURE (status)) { ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); @@ -295,8 +308,9 @@ acpi_ds_get_field_names ( + (acpi_integer) arg->common.value.size; if (position > ACPI_UINT32_MAX) { - ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", - (char *) &info->field_node->name)); + ACPI_REPORT_ERROR (( + "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", + (char *) &info->field_node->name)); return_ACPI_STATUS (AE_SUPPORT); } @@ -306,7 +320,8 @@ acpi_ds_get_field_names ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid opcode in field list: %X\n", arg->common.aml_opcode)); return_ACPI_STATUS (AE_AML_BAD_OPCODE); } @@ -435,7 +450,8 @@ acpi_ds_init_field_objects ( status = acpi_ns_lookup (walk_state->scope_info, (char *) &arg->named.name, type, ACPI_IMODE_LOAD_PASS1, - ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND, walk_state, &node); if (ACPI_FAILURE (status)) { ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index b4d264dbbf6..d7790db5017 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -49,12 +49,21 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsinit") +/* Local prototypes */ + +static acpi_status +acpi_ds_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + /******************************************************************************* * * FUNCTION: acpi_ds_init_one_object * - * PARAMETERS: obj_handle - Node + * PARAMETERS: obj_handle - Node for the object * Level - Current nesting level * Context - Points to a init info struct * return_value - Not used @@ -70,7 +79,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_init_one_object ( acpi_handle obj_handle, u32 level, @@ -105,7 +114,8 @@ acpi_ds_init_one_object ( status = acpi_ds_initialize_region (obj_handle); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Region %p [%4.4s] - Init failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); } @@ -118,8 +128,10 @@ acpi_ds_init_one_object ( info->method_count++; - /* Print a dot for each method unless we are going to print the entire pathname */ - + /* + * Print a dot for each method unless we are going to print + * the entire pathname + */ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); } @@ -140,7 +152,8 @@ acpi_ds_init_one_object ( */ status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Method %p [%4.4s] - parse failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); @@ -154,7 +167,8 @@ acpi_ds_init_one_object ( * for every execution since there isn't much overhead */ acpi_ns_delete_namespace_subtree (obj_handle); - acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); + acpi_ns_delete_namespace_by_owner ( + ((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); break; diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 9f0456cb9bb..9fc3f4c033e 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -153,12 +153,11 @@ acpi_ds_parse_method ( /* * Parse the method, first pass * - * The first pass load is where newly declared named objects are - * added into the namespace. Actual evaluation of - * the named objects (what would be called a "second - * pass") happens during the actual execution of the - * method so that operands to the named objects can - * take on dynamic run-time values. + * The first pass load is where newly declared named objects are added into + * the namespace. Actual evaluation of the named objects (what would be + * called a "second pass") happens during the actual execution of the + * method so that operands to the named objects can take on dynamic + * run-time values. */ status = acpi_ps_parse_aml (walk_state); if (ACPI_FAILURE (status)) { diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index f31d095f983..f7998306f75 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -52,6 +52,29 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsmthdat") +/* Local prototypes */ + +static void +acpi_ds_method_data_delete_value ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state); + +static acpi_status +acpi_ds_method_data_set_value ( + u16 opcode, + u32 index, + union acpi_operand_object *object, + struct acpi_walk_state *walk_state); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +acpi_object_type +acpi_ds_method_data_get_type ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state); +#endif + /******************************************************************************* * @@ -62,8 +85,8 @@ * RETURN: Status * * DESCRIPTION: Initialize the data structures that hold the method's arguments - * and locals. The data struct is an array of NTEs for each. - * This allows ref_of and de_ref_of to work properly for these + * and locals. The data struct is an array of namespace nodes for + * each - this allows ref_of and de_ref_of to work properly for these * special data types. * * NOTES: walk_state fields are initialized to zero by the @@ -92,7 +115,8 @@ acpi_ds_method_data_init ( walk_state->arguments[i].name.integer |= (i << 24); walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; walk_state->arguments[i].type = ACPI_TYPE_ANY; - walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; + walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | + ANOBJ_METHOD_ARG; } /* Init the method locals */ @@ -104,7 +128,8 @@ acpi_ds_method_data_init ( walk_state->local_variables[i].name.integer |= (i << 24); walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED; walk_state->local_variables[i].type = ACPI_TYPE_ANY; - walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; + walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | + ANOBJ_METHOD_LOCAL; } return_VOID; @@ -198,15 +223,18 @@ acpi_ds_method_data_init_args ( return_ACPI_STATUS (AE_OK); } - /* Copy passed parameters into the new method stack frame */ + /* Copy passed parameters into the new method stack frame */ - while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) { + while ((index < ACPI_METHOD_NUM_ARGS) && + (index < max_param_count) && + params[index]) { /* * A valid parameter. * Store the argument in the method/walk descriptor. * Do not copy the arg in order to implement call by reference */ - status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state); + status = acpi_ds_method_data_set_value (AML_ARG_OP, index, + params[index], walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -224,11 +252,13 @@ acpi_ds_method_data_init_args ( * FUNCTION: acpi_ds_method_data_get_node * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument whose type - * to get + * Index - Which Local or Arg whose type to get * walk_state - Current walk state object + * Node - Where the node is returned. * - * RETURN: Get the Node associated with a local or arg. + * RETURN: Status and node + * + * DESCRIPTION: Get the Node associated with a local or arg. * ******************************************************************************/ @@ -249,7 +279,8 @@ acpi_ds_method_data_get_node ( case AML_LOCAL_OP: if (index > ACPI_METHOD_MAX_LOCAL) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Local index %d is invalid (max %d)\n", index, ACPI_METHOD_MAX_LOCAL)); return_ACPI_STATUS (AE_AML_INVALID_INDEX); } @@ -262,7 +293,8 @@ acpi_ds_method_data_get_node ( case AML_ARG_OP: if (index > ACPI_METHOD_MAX_ARG) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Arg index %d is invalid (max %d)\n", index, ACPI_METHOD_MAX_ARG)); return_ACPI_STATUS (AE_AML_INVALID_INDEX); } @@ -286,7 +318,7 @@ acpi_ds_method_data_get_node ( * FUNCTION: acpi_ds_method_data_set_value * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to get + * Index - Which Local or Arg to get * Object - Object to be inserted into the stack entry * walk_state - Current walk state object * @@ -297,7 +329,7 @@ acpi_ds_method_data_get_node ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_method_data_set_value ( u16 opcode, u32 index, @@ -338,56 +370,6 @@ acpi_ds_method_data_set_value ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_method_data_get_type - * - * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument whose type - * to get - * walk_state - Current walk state object - * - * RETURN: Data type of current value of the selected Arg or Local - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_object_type -acpi_ds_method_data_get_type ( - u16 opcode, - u32 index, - struct acpi_walk_state *walk_state) -{ - acpi_status status; - struct acpi_namespace_node *node; - union acpi_operand_object *object; - - - ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); - - - /* Get the namespace node for the arg/local */ - - status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); - if (ACPI_FAILURE (status)) { - return_VALUE ((ACPI_TYPE_NOT_FOUND)); - } - - /* Get the object */ - - object = acpi_ns_get_attached_object (node); - if (!object) { - /* Uninitialized local/arg, return TYPE_ANY */ - - return_VALUE (ACPI_TYPE_ANY); - } - - /* Get the object type */ - - return_VALUE (ACPI_GET_OBJECT_TYPE (object)); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_method_data_get_value @@ -395,13 +377,11 @@ acpi_ds_method_data_get_type ( * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP * Index - which local_var or argument to get * walk_state - Current walk state object - * *dest_desc - Ptr to Descriptor into which selected Arg - * or Local value should be copied + * dest_desc - Where Arg or Local value is returned * * RETURN: Status * - * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame - * at the current top of the method stack. + * DESCRIPTION: Retrieve value of selected Arg or Local for this method * Used only in acpi_ex_resolve_to_value(). * ******************************************************************************/ @@ -467,14 +447,16 @@ acpi_ds_method_data_get_value ( else switch (opcode) { case AML_ARG_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Uninitialized Arg[%d] at node %p\n", index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); case AML_LOCAL_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Uninitialized Local[%d] at node %p\n", index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); @@ -506,12 +488,12 @@ acpi_ds_method_data_get_value ( * * RETURN: None * - * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts + * DESCRIPTION: Delete the entry at Opcode:Index. Inserts * a null into the stack slot after the object is deleted. * ******************************************************************************/ -void +static void acpi_ds_method_data_delete_value ( u16 opcode, u32 index, @@ -562,7 +544,7 @@ acpi_ds_method_data_delete_value ( * FUNCTION: acpi_ds_store_object_to_local * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to set + * Index - Which Local or Arg to set * obj_desc - Value to be stored * walk_state - Current walk state * @@ -651,19 +633,20 @@ acpi_ds_store_object_to_local ( */ if (opcode == AML_ARG_OP) { /* - * Make sure that the object is the correct type. This may be overkill, but - * it is here because references were NS nodes in the past. Now they are - * operand objects of type Reference. + * Make sure that the object is the correct type. This may be + * overkill, butit is here because references were NS nodes in + * the past. Now they are operand objects of type Reference. */ if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) { - ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n", - acpi_ut_get_descriptor_name (current_obj_desc))); + ACPI_REPORT_ERROR (( + "Invalid descriptor type while storing to method arg: [%s]\n", + acpi_ut_get_descriptor_name (current_obj_desc))); return_ACPI_STATUS (AE_AML_INTERNAL); } /* - * If we have a valid reference object that came from ref_of(), do the - * indirect store + * If we have a valid reference object that came from ref_of(), + * do the indirect store */ if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { @@ -713,3 +696,55 @@ acpi_ds_store_object_to_local ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_get_type + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which Local or Arg whose type to get + * walk_state - Current walk state object + * + * RETURN: Data type of current value of the selected Arg or Local + * + * DESCRIPTION: Get the type of the object stored in the Local or Arg + * + ******************************************************************************/ + +acpi_object_type +acpi_ds_method_data_get_type ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); + + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_VALUE ((ACPI_TYPE_NOT_FOUND)); + } + + /* Get the object */ + + object = acpi_ns_get_attached_object (node); + if (!object) { + /* Uninitialized local/arg, return TYPE_ANY */ + + return_VALUE (ACPI_TYPE_ANY); + } + + /* Get the object type */ + + return_VALUE (ACPI_GET_OBJECT_TYPE (object)); +} +#endif + + diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index eb8af4785bc..bfbae4e4c66 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -52,9 +52,15 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsobject") +static acpi_status +acpi_ds_build_internal_object ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object **obj_desc_ptr); + #ifndef ACPI_NO_METHOD_EXECUTION -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_object * @@ -67,9 +73,9 @@ * DESCRIPTION: Translate a parser Op object to the equivalent namespace object * Simple objects are any objects other than a package object! * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_build_internal_object ( struct acpi_walk_state *walk_state, union acpi_parse_object *op, @@ -90,9 +96,11 @@ acpi_ds_build_internal_object ( * Otherwise, go ahead and look it up now */ if (!op->common.node) { - status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, + status = acpi_ns_lookup (walk_state->scope_info, + op->common.value.string, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, (struct acpi_namespace_node **) &(op->common.node)); if (ACPI_FAILURE (status)) { @@ -104,12 +112,14 @@ acpi_ds_build_internal_object ( /* Create and init the internal ACPI object */ - obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); + obj_desc = acpi_ut_create_internal_object ( + (acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); if (!obj_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc); + status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, + &obj_desc); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); @@ -120,7 +130,7 @@ acpi_ds_build_internal_object ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_buffer_obj * @@ -134,7 +144,7 @@ acpi_ds_build_internal_object ( * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_build_internal_buffer_obj ( @@ -229,7 +239,7 @@ acpi_ds_build_internal_buffer_obj ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_package_obj * @@ -243,7 +253,7 @@ acpi_ds_build_internal_buffer_obj ( * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_build_internal_package_obj ( @@ -331,11 +341,12 @@ acpi_ds_build_internal_package_obj ( if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { /* Object (package or buffer) is already built */ - obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); + obj_desc->package.elements[i] = + ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); } else { status = acpi_ds_build_internal_object (walk_state, arg, - &obj_desc->package.elements[i]); + &obj_desc->package.elements[i]); } i++; @@ -348,7 +359,7 @@ acpi_ds_build_internal_package_obj ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_create_node * @@ -360,7 +371,7 @@ acpi_ds_build_internal_package_obj ( * * DESCRIPTION: Create the object to be associated with a namespace node * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_create_node ( @@ -392,7 +403,8 @@ acpi_ds_create_node ( /* Build an internal object for the argument(s) */ - status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc); + status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, + &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -414,7 +426,7 @@ acpi_ds_create_node ( #endif /* ACPI_NO_METHOD_EXECUTION */ -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_init_object_from_op * @@ -429,7 +441,7 @@ acpi_ds_create_node ( * associated arguments. The namespace object is a more compact * representation of the Op and its arguments. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_init_object_from_op ( @@ -462,7 +474,8 @@ acpi_ds_init_object_from_op ( /* * Defer evaluation of Buffer term_arg operand */ - obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->buffer.node = (struct acpi_namespace_node *) + walk_state->operands[0]; obj_desc->buffer.aml_start = op->named.data; obj_desc->buffer.aml_length = op->named.length; break; @@ -473,7 +486,8 @@ acpi_ds_init_object_from_op ( /* * Defer evaluation of Package term_arg operand */ - obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->package.node = (struct acpi_namespace_node *) + walk_state->operands[0]; obj_desc->package.aml_start = op->named.data; obj_desc->package.aml_length = op->named.length; break; @@ -486,9 +500,10 @@ acpi_ds_init_object_from_op ( /* * Resolve AML Constants here - AND ONLY HERE! * All constants are integers. - * We mark the integer with a flag that indicates that it started life - * as a constant -- so that stores to constants will perform as expected (noop). - * (zero_op is used as a placeholder for optional target operands.) + * We mark the integer with a flag that indicates that it started + * life as a constant -- so that stores to constants will perform + * as expected (noop). zero_op is used as a placeholder for optional + * target operands. */ obj_desc->common.flags = AOPOBJ_AML_CONSTANT; @@ -521,7 +536,8 @@ acpi_ds_init_object_from_op ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown constant opcode %X\n", opcode)); status = AE_AML_OPERAND_TYPE; break; } @@ -535,7 +551,8 @@ acpi_ds_init_object_from_op ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", + op_info->type)); status = AE_AML_OPERAND_TYPE; break; } @@ -570,8 +587,10 @@ acpi_ds_init_object_from_op ( obj_desc->reference.offset = opcode - AML_LOCAL_OP; #ifndef ACPI_NO_METHOD_EXECUTION - status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, - walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); + status = acpi_ds_method_data_get_node (AML_LOCAL_OP, + obj_desc->reference.offset, + walk_state, + (struct acpi_namespace_node **) &obj_desc->reference.object); #endif break; @@ -584,8 +603,10 @@ acpi_ds_init_object_from_op ( obj_desc->reference.offset = opcode - AML_ARG_OP; #ifndef ACPI_NO_METHOD_EXECUTION - status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset, - walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); + status = acpi_ds_method_data_get_node (AML_ARG_OP, + obj_desc->reference.offset, + walk_state, + (struct acpi_namespace_node **) &obj_desc->reference.object); #endif break; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 5c987a0e7b7..ba13bca28be 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -54,12 +54,31 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsopcode") +/* Local prototypes */ -/***************************************************************************** +static acpi_status +acpi_ds_execute_arguments ( + struct acpi_namespace_node *node, + struct acpi_namespace_node *scope_node, + u32 aml_length, + u8 *aml_start); + +static acpi_status +acpi_ds_init_buffer_field ( + u16 aml_opcode, + union acpi_operand_object *obj_desc, + union acpi_operand_object *buffer_desc, + union acpi_operand_object *offset_desc, + union acpi_operand_object *length_desc, + union acpi_operand_object *result_desc); + + +/******************************************************************************* * * FUNCTION: acpi_ds_execute_arguments * - * PARAMETERS: Node - Parent NS node + * PARAMETERS: Node - Object NS node + * scope_node - Parent NS node * aml_length - Length of executable AML * aml_start - Pointer to the AML * @@ -67,9 +86,9 @@ * * DESCRIPTION: Late (deferred) execution of region or field arguments * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_execute_arguments ( struct acpi_namespace_node *node, struct acpi_namespace_node *scope_node, @@ -162,7 +181,7 @@ acpi_ds_execute_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_buffer_field_arguments * @@ -173,7 +192,7 @@ acpi_ds_execute_arguments ( * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late * evaluation of these field attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_buffer_field_arguments ( @@ -208,7 +227,7 @@ acpi_ds_get_buffer_field_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_buffer_arguments * @@ -219,7 +238,7 @@ acpi_ds_get_buffer_field_arguments ( * DESCRIPTION: Get Buffer length and initializer byte list. This implements * the late evaluation of these attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_buffer_arguments ( @@ -255,7 +274,7 @@ acpi_ds_get_buffer_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_package_arguments * @@ -266,7 +285,7 @@ acpi_ds_get_buffer_arguments ( * DESCRIPTION: Get Package length and initializer byte list. This implements * the late evaluation of these attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_package_arguments ( @@ -353,17 +372,17 @@ acpi_ds_get_region_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_initialize_region * - * PARAMETERS: Op - A valid region Op object + * PARAMETERS: obj_handle - Region namespace node * * RETURN: Status * * DESCRIPTION: Front end to ev_initialize_region * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_initialize_region ( @@ -382,7 +401,7 @@ acpi_ds_initialize_region ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_init_buffer_field * @@ -390,16 +409,16 @@ acpi_ds_initialize_region ( * obj_desc - buffer_field object * buffer_desc - Host Buffer * offset_desc - Offset into buffer - * Length - Length of field (CREATE_FIELD_OP only) - * Result - Where to store the result + * length_desc - Length of field (CREATE_FIELD_OP only) + * result_desc - Where to store the result * * RETURN: Status * * DESCRIPTION: Perform actual initialization of a buffer field * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_init_buffer_field ( u16 aml_opcode, union acpi_operand_object *obj_desc, @@ -435,8 +454,10 @@ acpi_ds_init_buffer_field ( * after resolution in acpi_ex_resolve_operands(). */ if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n", - acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "(%s) destination not a NS Node [%s]\n", + acpi_ps_get_opcode_name (aml_opcode), + acpi_ut_get_descriptor_name (result_desc))); status = AE_AML_OPERAND_TYPE; goto cleanup; @@ -452,9 +473,18 @@ acpi_ds_init_buffer_field ( /* Offset is in bits, count is in bits */ + field_flags = AML_FIELD_ACCESS_BYTE; bit_offset = offset; bit_count = (u32) length_desc->integer.value; - field_flags = AML_FIELD_ACCESS_BYTE; + + /* Must have a valid (>0) bit count */ + + if (bit_count == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Attempt to create_field of length 0\n")); + status = AE_AML_OPERAND_VALUE; + goto cleanup; + } break; case AML_CREATE_BIT_FIELD_OP: @@ -527,7 +557,8 @@ acpi_ds_init_buffer_field ( /* * Initialize areas of the field object that are common to all fields - * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) + * For field_flags, use LOCK_RULE = 0 (NO_LOCK), + * UPDATE_RULE = 0 (UPDATE_PRESERVE) */ status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0, bit_offset, bit_count); @@ -539,8 +570,8 @@ acpi_ds_init_buffer_field ( /* Reference count for buffer_desc inherits obj_desc count */ - buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + - obj_desc->common.reference_count); + buffer_desc->common.reference_count = (u16) + (buffer_desc->common.reference_count + obj_desc->common.reference_count); cleanup: @@ -569,7 +600,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_buffer_field_operands * @@ -581,7 +612,7 @@ cleanup: * DESCRIPTION: Get buffer_field Buffer and Index * Called from acpi_ds_exec_end_op during buffer_field parse tree walk * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_buffer_field_operands ( @@ -656,7 +687,7 @@ acpi_ds_eval_buffer_field_operands ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_region_operands * @@ -668,7 +699,7 @@ acpi_ds_eval_buffer_field_operands ( * DESCRIPTION: Get region address and length * Called from acpi_ds_exec_end_op during op_region parse tree walk * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_region_operands ( @@ -686,7 +717,8 @@ acpi_ds_eval_region_operands ( /* - * This is where we evaluate the address and length fields of the op_region declaration + * This is where we evaluate the address and length fields of the + * op_region declaration */ node = op->common.node; @@ -707,7 +739,8 @@ acpi_ds_eval_region_operands ( /* Resolve the length and address operands to numbers */ - status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); + status = acpi_ex_resolve_operands (op->common.aml_opcode, + ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -736,7 +769,8 @@ acpi_ds_eval_region_operands ( */ operand_desc = walk_state->operands[walk_state->num_operands - 2]; - obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value; + obj_desc->region.address = (acpi_physical_address) + operand_desc->integer.value; acpi_ut_remove_reference (operand_desc); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", @@ -752,7 +786,7 @@ acpi_ds_eval_region_operands ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_data_object_operands * @@ -765,7 +799,7 @@ acpi_ds_eval_region_operands ( * DESCRIPTION: Get the operands and complete the following data object types: * Buffer, Package. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_data_object_operands ( @@ -830,7 +864,7 @@ acpi_ds_eval_data_object_operands ( if (ACPI_SUCCESS (status)) { /* - * Return the object in the walk_state, unless the parent is a package -- + * Return the object in the walk_state, unless the parent is a package - * in this case, the return object will be stored in the parse tree * for the package. */ @@ -988,7 +1022,8 @@ acpi_ds_exec_end_control_op ( status = AE_CTRL_PENDING; } - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[WHILE_OP] termination! Op=%p\n",op)); /* Pop this control state and free it */ diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 462c5d83e74..9613349ac31 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -100,7 +100,6 @@ acpi_ds_clear_implicit_return ( #ifndef ACPI_NO_METHOD_EXECUTION - /******************************************************************************* * * FUNCTION: acpi_ds_do_implicit_return @@ -205,7 +204,7 @@ acpi_ds_is_result_used ( * NOTE: this is optional because the ASL language does not actually * support this behavior. */ - acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); + (void) acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); /* * Now determine if the parent will use the result @@ -219,8 +218,9 @@ acpi_ds_is_result_used ( (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { /* No parent, the return value cannot possibly be used */ - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n", - acpi_ps_get_opcode_name (op->common.aml_opcode))); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "At Method level, result of [%s] not used\n", + acpi_ps_get_opcode_name (op->common.aml_opcode))); return_VALUE (FALSE); } @@ -228,7 +228,8 @@ acpi_ds_is_result_used ( parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); if (parent_info->class == AML_CLASS_UNKNOWN) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown parent opcode. Op=%p\n", op)); return_VALUE (FALSE); } @@ -309,17 +310,19 @@ acpi_ds_is_result_used ( result_used: - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", - acpi_ps_get_opcode_name (op->common.aml_opcode), - acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); return_VALUE (TRUE); result_not_used: - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", - acpi_ps_get_opcode_name (op->common.aml_opcode), - acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] not used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); return_VALUE (FALSE); } @@ -522,7 +525,8 @@ acpi_ds_create_operand ( if ((walk_state->deferred_node) && (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) && (arg_index != 0)) { - obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node); + obj_desc = ACPI_CAST_PTR ( + union acpi_operand_object, walk_state->deferred_node); status = AE_OK; } else /* All other opcodes */ { @@ -565,7 +569,8 @@ acpi_ds_create_operand ( * indicate this to the interpreter, set the * object to the root */ - obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node); + obj_desc = ACPI_CAST_PTR ( + union acpi_operand_object, acpi_gbl_root_node); status = AE_OK; } else { @@ -612,7 +617,8 @@ acpi_ds_create_operand ( */ opcode = AML_ZERO_OP; /* Has no arguments! */ - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Null namepath: Arg=%p\n", arg)); } else { opcode = arg->common.aml_opcode; @@ -642,7 +648,8 @@ acpi_ds_create_operand ( * Only error is underflow, and this indicates * a missing or null operand! */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Missing or null operand, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -657,8 +664,8 @@ acpi_ds_create_operand ( /* Initialize the new object */ - status = acpi_ds_init_object_from_op (walk_state, arg, - opcode, &obj_desc); + status = acpi_ds_init_object_from_op ( + walk_state, arg, opcode, &obj_desc); if (ACPI_FAILURE (status)) { acpi_ut_delete_object_desc (obj_desc); return_ACPI_STATUS (status); diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 2071a0d2bbb..10f71318e23 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -73,11 +73,13 @@ static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { acpi_ex_opcode_3A_1T_1R, acpi_ex_opcode_6A_0T_1R}; + /***************************************************************************** * * FUNCTION: acpi_ds_get_predicate_value * * PARAMETERS: walk_state - Current state of the parse tree walk + * result_obj - if non-zero, pop result from result stack * * RETURN: Status * @@ -124,7 +126,8 @@ acpi_ds_get_predicate_value ( } if (!obj_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No predicate obj_desc=%p State=%p\n", obj_desc, walk_state)); return_ACPI_STATUS (AE_AML_NO_OPERAND); @@ -197,7 +200,7 @@ cleanup: * FUNCTION: acpi_ds_exec_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * out_op - Return op if a new one is created + * out_op - Where to return op if a new one is created * * RETURN: Status * @@ -233,7 +236,8 @@ acpi_ds_exec_begin_op ( walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (acpi_ns_opens_scope (walk_state->op_info->object_type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "(%s) Popping scope for Op %p\n", acpi_ut_get_type_name (walk_state->op_info->object_type), op)); status = acpi_ds_scope_stack_pop (walk_state); @@ -297,11 +301,10 @@ acpi_ds_exec_begin_op ( if (walk_state->walk_type == ACPI_WALK_METHOD) { /* - * Found a named object declaration during method - * execution; we must enter this object into the - * namespace. The created object is temporary and - * will be deleted upon completion of the execution - * of this method. + * Found a named object declaration during method execution; + * we must enter this object into the namespace. The created + * object is temporary and will be deleted upon completion of + * the execution of this method. */ status = acpi_ds_load2_begin_op (walk_state, NULL); } @@ -338,8 +341,6 @@ acpi_ds_exec_begin_op ( * FUNCTION: acpi_ds_exec_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -389,7 +390,7 @@ acpi_ds_exec_end_op ( /* Decode the Opcode Class */ switch (op_class) { - case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */ + case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */ break; @@ -417,12 +418,12 @@ acpi_ds_exec_end_op ( /* Resolve all operands */ status = acpi_ex_resolve_operands (walk_state->opcode, - &(walk_state->operands [walk_state->num_operands -1]), - walk_state); + &(walk_state->operands [walk_state->num_operands -1]), + walk_state); if (ACPI_SUCCESS (status)) { ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, - acpi_ps_get_opcode_name (walk_state->opcode), - walk_state->num_operands, "after ex_resolve_operands"); + acpi_ps_get_opcode_name (walk_state->opcode), + walk_state->num_operands, "after ex_resolve_operands"); } } @@ -506,7 +507,8 @@ acpi_ds_exec_end_op ( if ((op->asl.parent) && ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) || (op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Method Reference in a Package, Op=%p\n", op)); op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object; acpi_ut_add_reference (op->asl.value.arg->asl.node->object); return_ACPI_STATUS (AE_OK); @@ -583,13 +585,15 @@ acpi_ds_exec_end_op ( case AML_NAME_OP: /* - * Put the Node on the object stack (Contains the ACPI Name of - * this object) + * Put the Node on the object stack (Contains the ACPI Name + * of this object) */ walk_state->operands[0] = (void *) op->common.parent->common.node; walk_state->num_operands = 1; - status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent); + status = acpi_ds_create_node (walk_state, + op->common.parent->common.node, + op->common.parent); if (ACPI_FAILURE (status)) { break; } @@ -600,7 +604,7 @@ acpi_ds_exec_end_op ( case AML_INT_EVAL_SUBTREE_OP: status = acpi_ds_eval_data_object_operands (walk_state, op, - acpi_ns_get_attached_object (op->common.parent->common.node)); + acpi_ns_get_attached_object (op->common.parent->common.node)); break; default: @@ -609,7 +613,7 @@ acpi_ds_exec_end_op ( break; } - /* Done with this result state (Now that operand stack is built) */ + /* Done with result state (Now that operand stack is built) */ status = acpi_ds_result_stack_pop (walk_state); if (ACPI_FAILURE (status)) { @@ -620,8 +624,7 @@ acpi_ds_exec_end_op ( * If a result object was returned from above, push it on the * current result stack */ - if (ACPI_SUCCESS (status) && - walk_state->result_obj) { + if (walk_state->result_obj) { status = acpi_ds_result_push (walk_state->result_obj, walk_state); } break; @@ -654,7 +657,8 @@ acpi_ds_exec_end_op ( case AML_TYPE_UNDEFINED: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Undefined opcode type Op=%p\n", op)); return_ACPI_STATUS (AE_NOT_IMPLEMENTED); @@ -709,13 +713,14 @@ cleanup: status = acpi_gbl_exception_handler (status, walk_state->method_node->name.integer, walk_state->opcode, walk_state->aml_offset, NULL); - acpi_ex_enter_interpreter (); + (void) acpi_ex_enter_interpreter (); } if (walk_state->result_obj) { /* Break to debugger to display result */ - ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, + walk_state)); /* * Delete the result op if and only if: diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 06d75867958..1ac197ccfc8 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -79,20 +79,23 @@ acpi_ds_init_callbacks ( switch (pass_number) { case 1: - walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load1_begin_op; walk_state->ascending_callback = acpi_ds_load1_end_op; break; case 2: - walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load2_begin_op; walk_state->ascending_callback = acpi_ds_load2_end_op; break; case 3: #ifndef ACPI_NO_METHOD_EXECUTION - walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags |= ACPI_PARSE_EXECUTE | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_exec_begin_op; walk_state->ascending_callback = acpi_ds_exec_end_op; #endif @@ -111,8 +114,7 @@ acpi_ds_init_callbacks ( * FUNCTION: acpi_ds_load1_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been reached in the - * walk; Arguments have not been evaluated yet. + * out_op - Where to return op if a new one is created * * RETURN: Status * @@ -146,7 +148,8 @@ acpi_ds_load1_begin_op ( #if 0 if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || (walk_state->op_info->class == AML_CLASS_CONTROL)) { - acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name); + acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", + walk_state->op_info->name); *out_op = op; return (AE_CTRL_SKIP); } @@ -191,7 +194,8 @@ acpi_ds_load1_begin_op ( */ acpi_dm_add_to_external_list (path); status = acpi_ns_lookup (walk_state->scope_info, path, object_type, - ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); } #endif if (ACPI_FAILURE (status)) { @@ -224,10 +228,12 @@ acpi_ds_load1_begin_op ( * Name (DEB, 0) * Scope (DEB) { ... } * - * Note: silently change the type here. On the second pass, we will report a warning + * Note: silently change the type here. On the second pass, we will report + * a warning */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", path, acpi_ut_get_type_name (node->type))); node->type = ACPI_TYPE_ANY; @@ -238,7 +244,8 @@ acpi_ds_load1_begin_op ( /* All other types are an error */ - ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", + ACPI_REPORT_ERROR (( + "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", acpi_ut_get_type_name (node->type), path)); return (AE_AML_OPERAND_TYPE); @@ -249,7 +256,8 @@ acpi_ds_load1_begin_op ( default: /* - * For all other named opcodes, we will enter the name into the namespace. + * For all other named opcodes, we will enter the name into + * the namespace. * * Setup the search flags. * Since we are entering a name into the namespace, we do not want to @@ -279,14 +287,16 @@ acpi_ds_load1_begin_op ( acpi_ut_get_type_name (object_type))); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[%s] Both Find or Create allowed\n", acpi_ut_get_type_name (object_type))); } /* * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that involve - * arguments to the opcode must be created as we go back up the parse tree later. + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. */ status = acpi_ns_lookup (walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node)); @@ -335,8 +345,6 @@ acpi_ds_load1_begin_op ( * FUNCTION: acpi_ds_load1_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -383,7 +391,9 @@ acpi_ds_load1_end_op ( if (op->common.aml_opcode == AML_REGION_OP) { status = acpi_ex_create_region (op->named.data, op->named.length, - (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state); + (acpi_adr_space_type) + ((op->common.value.arg)->common.value.integer), + walk_state); if (ACPI_FAILURE (status)) { return (status); } @@ -394,7 +404,8 @@ acpi_ds_load1_end_op ( /* For Name opcode, get the object type from the argument */ if (op->common.value.arg) { - object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type; + object_type = (acpi_ps_get_opcode_info ( + (op->common.value.arg)->common.aml_opcode))->object_type; op->common.node->type = (u8) object_type; } } @@ -448,8 +459,7 @@ acpi_ds_load1_end_op ( * FUNCTION: acpi_ds_load2_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been reached in the - * walk; Arguments have not been evaluated yet. + * out_op - Wher to return op if a new one is created * * RETURN: Status * @@ -478,14 +488,20 @@ acpi_ds_load2_begin_op ( if (op) { /* We only care about Namespace opcodes here */ - if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || + if ((!(walk_state->op_info->flags & AML_NSOPCODE) && + (walk_state->opcode != AML_INT_NAMEPATH_OP)) || (!(walk_state->op_info->flags & AML_NAMED))) { + if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || + (walk_state->op_info->class == AML_CLASS_CONTROL)) { + ACPI_REPORT_WARNING (( + "Encountered executable code at module level, [%s]\n", + acpi_ps_get_opcode_name (walk_state->opcode))); + } return_ACPI_STATUS (AE_OK); } - /* - * Get the name we are going to enter or lookup in the namespace - */ + /* Get the name we are going to enter or lookup in the namespace */ + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { /* For Namepath op, get the path string */ @@ -528,21 +544,25 @@ acpi_ds_load2_begin_op ( case AML_INT_NAMEPATH_OP: /* - * The name_path is an object reference to an existing object. Don't enter the - * name into the namespace, but look it up for use later + * The name_path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. */ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); break; case AML_SCOPE_OP: /* - * The Path is an object reference to an existing object. Don't enter the - * name into the namespace, but look it up for use later + * The Path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. */ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); if (ACPI_FAILURE (status)) { #ifdef _ACPI_ASL_COMPILER if (status == AE_NOT_FOUND) { @@ -582,7 +602,8 @@ acpi_ds_load2_begin_op ( * Scope (DEB) { ... } */ - ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + ACPI_REPORT_WARNING (( + "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", buffer_ptr, acpi_ut_get_type_name (node->type))); node->type = ACPI_TYPE_ANY; @@ -593,7 +614,8 @@ acpi_ds_load2_begin_op ( /* All other types are an error */ - ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", + ACPI_REPORT_ERROR (( + "Invalid type (%s) for target of Scope operator [%4.4s]\n", acpi_ut_get_type_name (node->type), buffer_ptr)); return (AE_AML_OPERAND_TYPE); @@ -621,8 +643,9 @@ acpi_ds_load2_begin_op ( /* * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that involve - * arguments to the opcode must be created as we go back up the parse tree later. + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. * * Note: Name may already exist if we are executing a deferred opcode. */ @@ -635,7 +658,8 @@ acpi_ds_load2_begin_op ( } status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, + walk_state, &(node)); break; } @@ -678,8 +702,6 @@ acpi_ds_load2_begin_op ( * FUNCTION: acpi_ds_load2_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -738,7 +760,8 @@ acpi_ds_load2_end_op ( /* Pop the scope stack */ - if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { + if (acpi_ns_opens_scope (object_type) && + (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", acpi_ut_get_type_name (object_type), op)); @@ -803,7 +826,7 @@ acpi_ds_load2_end_op ( case AML_INDEX_FIELD_OP: status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node, - walk_state); + walk_state); break; case AML_BANK_FIELD_OP: @@ -884,14 +907,16 @@ acpi_ds_load2_end_op ( #ifndef ACPI_NO_METHOD_EXECUTION case AML_REGION_OP: /* - * The op_region is not fully parsed at this time. Only valid argument is the space_id. - * (We must save the address of the AML of the address and length operands) + * The op_region is not fully parsed at this time. Only valid + * argument is the space_id. (We must save the address of the + * AML of the address and length operands) */ /* * If we have a valid region, initialize it * Namespace is NOT locked at this point. */ - status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE); + status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), + FALSE); if (ACPI_FAILURE (status)) { /* * If AE_NOT_EXIST is returned, it is not fatal @@ -942,15 +967,16 @@ acpi_ds_load2_end_op ( if (ACPI_SUCCESS (status)) { /* * Make sure that what we found is indeed a method - * We didn't search for a method on purpose, to see if the name would resolve + * We didn't search for a method on purpose, to see if the name + * would resolve */ if (new_node->type != ACPI_TYPE_METHOD) { status = AE_AML_OPERAND_TYPE; } - /* We could put the returned object (Node) on the object stack for later, but - * for now, we will put it in the "op" object that the parser uses, so we - * can get it again at the end of this scope + /* We could put the returned object (Node) on the object stack for + * later, but for now, we will put it in the "op" object that the + * parser uses, so we can get it again at the end of this scope */ op->common.node = new_node; } diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index 65f456151e2..21f4548ff32 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -50,14 +50,13 @@ ACPI_MODULE_NAME ("dswscope") -#define STACK_POP(head) head - - /**************************************************************************** * * FUNCTION: acpi_ds_scope_stack_clear * - * PARAMETERS: None + * PARAMETERS: walk_state - Current state + * + * RETURN: None * * DESCRIPTION: Pop (and free) everything on the scope stack except the * root scope object (which remains at the stack top.) @@ -80,7 +79,8 @@ acpi_ds_scope_stack_clear ( walk_state->scope_info = scope_info->scope.next; ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value))); + "Popped object type (%s)\n", + acpi_ut_get_type_name (scope_info->common.value))); acpi_ut_delete_generic_state (scope_info); } } @@ -90,8 +90,11 @@ acpi_ds_scope_stack_clear ( * * FUNCTION: acpi_ds_scope_stack_push * - * PARAMETERS: *Node, - Name to be made current - * Type, - Type of frame being pushed + * PARAMETERS: Node - Name to be made current + * Type - Type of frame being pushed + * walk_state - Current state + * + * RETURN: Status * * DESCRIPTION: Push the current scope on the scope stack, and make the * passed Node current. @@ -121,7 +124,8 @@ acpi_ds_scope_stack_push ( /* Make sure object type is valid */ if (!acpi_ut_valid_object_type (type)) { - ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type)); + ACPI_REPORT_WARNING (( + "ds_scope_stack_push: Invalid object type: 0x%X\n", type)); } /* Allocate a new scope object */ @@ -170,16 +174,11 @@ acpi_ds_scope_stack_push ( * * FUNCTION: acpi_ds_scope_stack_pop * - * PARAMETERS: Type - The type of frame to be found + * PARAMETERS: walk_state - Current state * - * DESCRIPTION: Pop the scope stack until a frame of the requested type - * is found. + * RETURN: Status * - * RETURN: Count of frames popped. If no frame of the requested type - * was found, the count is returned as a negative number and - * the scope stack is emptied (which sets the current scope - * to the root). If the scope stack was empty at entry, the - * function is a no-op and returns 0. + * DESCRIPTION: Pop the scope stack once. * ***************************************************************************/ diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index e555b3fbd5e..9cd3db652b3 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -50,67 +50,31 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dswstate") +/* Local prototypes */ -#ifdef ACPI_FUTURE_USAGE - -/******************************************************************************* - * - * FUNCTION: acpi_ds_result_insert - * - * PARAMETERS: Object - Object to push - * Index - Where to insert the object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Insert an object onto this walk's result stack - * - ******************************************************************************/ - +#ifdef ACPI_OBSOLETE_FUNCTIONS acpi_status acpi_ds_result_insert ( void *object, u32 index, - struct acpi_walk_state *walk_state) -{ - union acpi_generic_state *state; - + struct acpi_walk_state *walk_state); - ACPI_FUNCTION_NAME ("ds_result_insert"); - - - state = walk_state->results; - if (!state) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", - walk_state)); - return (AE_NOT_EXIST); - } - - if (index >= ACPI_OBJ_NUM_OPERANDS) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index out of range: %X Obj=%p State=%p Num=%X\n", - index, object, walk_state, state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - if (!object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Null Object! Index=%X Obj=%p State=%p Num=%X\n", - index, object, walk_state, state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - state->results.obj_desc [index] = object; - state->results.num_results++; +acpi_status +acpi_ds_obj_stack_delete_all ( + struct acpi_walk_state *walk_state); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Obj=%p [%s] State=%p Num=%X Cur=%X\n", - object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", - walk_state, state->results.num_results, walk_state->current_result)); +acpi_status +acpi_ds_obj_stack_pop_object ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state); - return (AE_OK); -} +void * +acpi_ds_obj_stack_get_value ( + u32 index, + struct acpi_walk_state *walk_state); +#endif +#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -178,7 +142,6 @@ acpi_ds_result_remove ( #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_ds_result_pop @@ -227,15 +190,18 @@ acpi_ds_result_pop ( *object = state->results.obj_desc [index -1]; state->results.obj_desc [index -1] = NULL; - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n", - *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] Index=%X State=%p Num=%X\n", + *object, + (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", (u32) index -1, walk_state, state->results.num_results)); return (AE_OK); } } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No result objects! State=%p\n", walk_state)); return (AE_AML_NO_RETURN_VALUE); } @@ -274,7 +240,8 @@ acpi_ds_result_pop_from_bottom ( } if (!state->results.num_results) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", + walk_state)); return (AE_AML_NO_RETURN_VALUE); } @@ -293,7 +260,8 @@ acpi_ds_result_pop_from_bottom ( /* Check for a valid result object */ if (!*object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X, Index=%X\n", walk_state, state->results.num_results, (u32) index)); return (AE_AML_NO_RETURN_VALUE); } @@ -344,7 +312,8 @@ acpi_ds_result_push ( } if (!object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null Object! Obj=%p State=%p Num=%X\n", object, walk_state, state->results.num_results)); return (AE_BAD_PARAMETER); } @@ -437,43 +406,6 @@ acpi_ds_result_stack_pop ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_delete_all - * - * PARAMETERS: walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Clear the object stack by deleting all objects that are on it. - * Should be used with great care, if at all! - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_status -acpi_ds_obj_stack_delete_all ( - struct acpi_walk_state *walk_state) -{ - u32 i; - - - ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); - - - /* The stack size is configurable, but fixed */ - - for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { - if (walk_state->operands[i]) { - acpi_ut_remove_reference (walk_state->operands[i]); - walk_state->operands[i] = NULL; - } - } - - return_ACPI_STATUS (AE_OK); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_obj_stack_push @@ -517,67 +449,6 @@ acpi_ds_obj_stack_push ( } -#if 0 -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_pop_object - * - * PARAMETERS: pop_count - Number of objects/entries to pop - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT - * deleted by this routine. - * - ******************************************************************************/ - -acpi_status -acpi_ds_obj_stack_pop_object ( - union acpi_operand_object **object, - struct acpi_walk_state *walk_state) -{ - ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); - - - /* Check for stack underflow */ - - if (walk_state->num_operands == 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Missing operand/stack empty! State=%p #Ops=%X\n", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Pop the stack */ - - walk_state->num_operands--; - - /* Check for a valid operand */ - - if (!walk_state->operands [walk_state->num_operands]) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Null operand! State=%p #Ops=%X\n", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Get operand and set stack entry to null */ - - *object = walk_state->operands [walk_state->num_operands]; - walk_state->operands [walk_state->num_operands] = NULL; - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", - *object, acpi_ut_get_object_type_name (*object), - walk_state, walk_state->num_operands)); - - return (AE_OK); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ds_obj_stack_pop @@ -678,48 +549,6 @@ acpi_ds_obj_stack_pop_and_delete ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_get_value - * - * PARAMETERS: Index - Stack index whose value is desired. Based - * on the top of the stack (index=0 == top) - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Retrieve an object from this walk's object stack. Index must - * be within the range of the current stack pointer. - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -void * -acpi_ds_obj_stack_get_value ( - u32 index, - struct acpi_walk_state *walk_state) -{ - - ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); - - - /* Can't do it if the stack is empty */ - - if (walk_state->num_operands == 0) { - return_PTR (NULL); - } - - /* or if the index is past the top of the stack */ - - if (index > (walk_state->num_operands - (u32) 1)) { - return_PTR (NULL); - } - - return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - - index]); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_get_current_walk_state @@ -757,11 +586,11 @@ acpi_ds_get_current_walk_state ( * FUNCTION: acpi_ds_push_walk_state * * PARAMETERS: walk_state - State to push - * walk_list - The list that owns the walk stack + * Thread - Thread state object * * RETURN: None * - * DESCRIPTION: Place the walk_state at the head of the state list. + * DESCRIPTION: Place the Thread state at the head of the state list. * ******************************************************************************/ @@ -784,9 +613,9 @@ acpi_ds_push_walk_state ( * * FUNCTION: acpi_ds_pop_walk_state * - * PARAMETERS: walk_list - The list that owns the walk stack + * PARAMETERS: Thread - Current thread state * - * RETURN: A walk_state object popped from the stack + * RETURN: A walk_state object popped from the thread's stack * * DESCRIPTION: Remove and return the walkstate object that is at the head of * the walk stack for the given walk list. NULL indicates that @@ -814,7 +643,7 @@ acpi_ds_pop_walk_state ( /* * Don't clear the NEXT field, this serves as an indicator * that there is a parent WALK STATE - * NO: walk_state->Next = NULL; + * Do Not: walk_state->Next = NULL; */ } @@ -826,7 +655,9 @@ acpi_ds_pop_walk_state ( * * FUNCTION: acpi_ds_create_walk_state * - * PARAMETERS: Origin - Starting point for this walk + * PARAMETERS: owner_id - ID for object creation + * Origin - Starting point for this walk + * mth_desc - Method object * Thread - Current thread state * * RETURN: Pointer to the new walk state. @@ -896,8 +727,7 @@ acpi_ds_create_walk_state ( * method_node - Control method NS node, if any * aml_start - Start of AML * aml_length - Length of AML - * Params - Method args, if any - * return_obj_desc - Where to store a return object, if any + * Info - Method info block (params, etc.) * pass_number - 1, 2, or 3 * * RETURN: Status @@ -931,7 +761,7 @@ acpi_ds_init_aml_walk ( /* The next_op of the next_walk will be the beginning of the method */ - walk_state->next_op = NULL; + walk_state->next_op = NULL; if (info) { if (info->parameter_type == ACPI_PARAM_GPE) { @@ -939,8 +769,8 @@ acpi_ds_init_aml_walk ( info->parameters); } else { - walk_state->params = info->parameters; - walk_state->caller_return_desc = &info->return_object; + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; } } @@ -964,7 +794,8 @@ acpi_ds_init_aml_walk ( /* Init the method arguments */ - status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (walk_state->params, + ACPI_METHOD_NUM_ARGS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -1031,12 +862,14 @@ acpi_ds_delete_walk_state ( } if (walk_state->data_type != ACPI_DESC_TYPE_WALK) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", + walk_state)); return; } if (walk_state->parser_state.scope) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", + walk_state)); } /* Always must free any linked control states */ @@ -1078,7 +911,7 @@ acpi_ds_delete_walk_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Purge the global state object cache. Used during subsystem * termination. @@ -1098,3 +931,200 @@ acpi_ds_delete_walk_state_cache ( #endif +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_insert + * + * PARAMETERS: Object - Object to push + * Index - Where to insert the object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Insert an object onto this walk's result stack + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_insert ( + void *object, + u32 index, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_insert"); + + + state = walk_state->results; + if (!state) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", + walk_state)); + return (AE_NOT_EXIST); + } + + if (index >= ACPI_OBJ_NUM_OPERANDS) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index out of range: %X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + if (!object) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null Object! Index=%X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + state->results.obj_desc [index] = object; + state->results.num_results++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] State=%p Num=%X Cur=%X\n", + object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", + walk_state, state->results.num_results, walk_state->current_result)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_delete_all + * + * PARAMETERS: walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Clear the object stack by deleting all objects that are on it. + * Should be used with great care, if at all! + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_delete_all ( + struct acpi_walk_state *walk_state) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); + + + /* The stack size is configurable, but fixed */ + + for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { + if (walk_state->operands[i]) { + acpi_ut_remove_reference (walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_pop_object + * + * PARAMETERS: Object - Where to return the popped object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * deleted by this routine. + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_pop_object ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state) +{ + ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); + + + /* Check for stack underflow */ + + if (walk_state->num_operands == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Missing operand/stack empty! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Pop the stack */ + + walk_state->num_operands--; + + /* Check for a valid operand */ + + if (!walk_state->operands [walk_state->num_operands]) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Get operand and set stack entry to null */ + + *object = walk_state->operands [walk_state->num_operands]; + walk_state->operands [walk_state->num_operands] = NULL; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", + *object, acpi_ut_get_object_type_name (*object), + walk_state, walk_state->num_operands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_get_value + * + * PARAMETERS: Index - Stack index whose value is desired. Based + * on the top of the stack (index=0 == top) + * walk_state - Current Walk state + * + * RETURN: Pointer to the requested operand + * + * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must + * be within the range of the current stack pointer. + * + ******************************************************************************/ + +void * +acpi_ds_obj_stack_get_value ( + u32 index, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); + + + /* Can't do it if the stack is empty */ + + if (walk_state->num_operands == 0) { + return_PTR (NULL); + } + + /* or if the index is past the top of the stack */ + + if (index > (walk_state->num_operands - (u32) 1)) { + return_PTR (NULL); + } + + return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - + index]); +} +#endif + + diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index 2a213604ae5..dd3a72a869f 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -47,6 +47,16 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evevent") +/* Local prototypes */ + +static acpi_status +acpi_ev_fixed_event_initialize ( + void); + +static u32 +acpi_ev_fixed_event_dispatch ( + u32 event); + /******************************************************************************* * @@ -56,7 +66,7 @@ * * RETURN: Status * - * DESCRIPTION: Initialize global data structures for events. + * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE) * ******************************************************************************/ @@ -78,9 +88,9 @@ acpi_ev_initialize_events ( } /* - * Initialize the Fixed and General Purpose Events. This is - * done prior to enabling SCIs to prevent interrupts from - * occurring before handers are installed. + * Initialize the Fixed and General Purpose Events. This is done prior to + * enabling SCIs to prevent interrupts from occurring before the handlers are + * installed. */ status = acpi_ev_fixed_event_initialize (); if (ACPI_FAILURE (status)) { @@ -161,7 +171,7 @@ acpi_ev_install_xrupt_handlers ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_fixed_event_initialize ( void) { @@ -180,7 +190,8 @@ acpi_ev_fixed_event_initialize ( /* Enable the fixed event */ if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { - status = acpi_set_register (acpi_gbl_fixed_event_info[i].enable_register_id, + status = acpi_set_register ( + acpi_gbl_fixed_event_info[i].enable_register_id, 0, ACPI_MTX_LOCK); if (ACPI_FAILURE (status)) { return (status); @@ -200,7 +211,7 @@ acpi_ev_fixed_event_initialize ( * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Checks the PM status register for fixed events + * DESCRIPTION: Checks the PM status register for active fixed events * ******************************************************************************/ @@ -221,8 +232,10 @@ acpi_ev_fixed_event_detect ( * Read the fixed feature status and enable registers, as all the cases * depend on their values. Ignore errors here. */ - (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &fixed_status); - (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, + &fixed_status); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, + &fixed_enable); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", @@ -259,7 +272,7 @@ acpi_ev_fixed_event_detect ( * ******************************************************************************/ -u32 +static u32 acpi_ev_fixed_event_dispatch ( u32 event) { diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 118d72ac7c7..081120b109b 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -48,6 +48,12 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evgpe") +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +acpi_ev_asynch_execute_gpe_method ( + void *context); + /******************************************************************************* * @@ -335,8 +341,10 @@ acpi_ev_get_gpe_event_info ( gpe_block = acpi_gbl_gpe_fadt_blocks[i]; if (gpe_block) { if ((gpe_number >= gpe_block->block_base_number) && - (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]); + (gpe_number < gpe_block->block_base_number + + (gpe_block->register_count * 8))) { + return (&gpe_block->event_info[gpe_number - + gpe_block->block_base_number]); } } } @@ -437,7 +445,7 @@ acpi_ev_gpe_detect ( "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n", gpe_register_info->base_gpe_number, status_reg, enable_reg)); - /* First check if there is anything active at all in this register */ + /* Check if there is anything active at all in this register */ enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { @@ -457,8 +465,8 @@ acpi_ev_gpe_detect ( * or method. */ int_status |= acpi_ev_gpe_dispatch ( - &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], - (u32) j + gpe_register_info->base_gpe_number); + &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], + (u32) j + gpe_register_info->base_gpe_number); } } } @@ -523,7 +531,8 @@ acpi_ev_asynch_execute_gpe_method ( * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. */ - ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info)); + ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, + sizeof (struct acpi_gpe_event_info)); status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { @@ -534,7 +543,8 @@ acpi_ev_asynch_execute_gpe_method ( * Must check for control method type dispatch one more * time to avoid race with ev_gpe_install_handler */ - if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { + if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_METHOD) { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx * control method that corresponds to this GPE @@ -553,7 +563,8 @@ acpi_ev_asynch_execute_gpe_method ( } } - if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { + if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after * handling the event. @@ -575,7 +586,7 @@ acpi_ev_asynch_execute_gpe_method ( * * FUNCTION: acpi_ev_gpe_dispatch * - * PARAMETERS: gpe_event_info - info for this GPE + * PARAMETERS: gpe_event_info - Info for this GPE * gpe_number - Number relative to the parent GPE block * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED @@ -602,10 +613,12 @@ acpi_ev_gpe_dispatch ( * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n", acpi_format_exception (status), gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } @@ -639,7 +652,8 @@ acpi_ev_gpe_dispatch ( /* It is now safe to clear level-triggered events. */ - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( @@ -704,7 +718,6 @@ acpi_ev_gpe_dispatch ( #ifdef ACPI_GPE_NOTIFY_CHECK - /******************************************************************************* * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED * diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 00d981f53c6..84186a7d17b 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -48,6 +48,39 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evgpeblk") +/* Local prototypes */ + +static acpi_status +acpi_ev_save_method_info ( + acpi_handle obj_handle, + u32 level, + void *obj_desc, + void **return_value); + +static acpi_status +acpi_ev_match_prw_and_gpe ( + acpi_handle obj_handle, + u32 level, + void *info, + void **return_value); + +static struct acpi_gpe_xrupt_info * +acpi_ev_get_gpe_xrupt_block ( + u32 interrupt_level); + +static acpi_status +acpi_ev_delete_gpe_xrupt ( + struct acpi_gpe_xrupt_info *gpe_xrupt); + +static acpi_status +acpi_ev_install_gpe_block ( + struct acpi_gpe_block_info *gpe_block, + u32 interrupt_level); + +static acpi_status +acpi_ev_create_gpe_info_blocks ( + struct acpi_gpe_block_info *gpe_block); + /******************************************************************************* * @@ -155,7 +188,7 @@ unlock_and_exit: } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ev_delete_gpe_handlers * @@ -190,7 +223,8 @@ acpi_ev_delete_gpe_handlers ( for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_HANDLER) { ACPI_MEM_FREE (gpe_event_info->dispatch.handler); gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; @@ -471,7 +505,7 @@ acpi_ev_get_gpe_xrupt_block ( ACPI_FUNCTION_TRACE ("ev_get_gpe_xrupt_block"); - /* No need for spin lock since we are not changing any list elements here */ + /* No need for lock since we are not changing any list elements here */ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { @@ -619,7 +653,7 @@ acpi_ev_install_gpe_block ( goto unlock_and_exit; } - /* Install the new block at the end of the list for this interrupt with lock */ + /* Install the new block at the end of the list with lock */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); if (gpe_xrupt_block->gpe_block_list_head) { @@ -756,10 +790,12 @@ acpi_ev_create_gpe_info_blocks ( * per register. Initialization to zeros is sufficient. */ gpe_event_info = ACPI_MEM_CALLOCATE ( - ((acpi_size) gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) * + ((acpi_size) gpe_block->register_count * + ACPI_GPE_REGISTER_WIDTH) * sizeof (struct acpi_gpe_event_info)); if (!gpe_event_info) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the gpe_event_info table\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not allocate the gpe_event_info table\n")); status = AE_NO_MEMORY; goto error_exit; } @@ -899,7 +935,8 @@ acpi_ev_create_gpe_block ( gpe_block->block_base_number = gpe_block_base_number; gpe_block->node = gpe_device; - ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address)); + ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, + sizeof (struct acpi_generic_address)); /* Create the register_info and event_info sub-structures */ @@ -1061,8 +1098,9 @@ acpi_ev_gpe_initialize ( /* Install GPE Block 0 */ - status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk, - register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, + &acpi_gbl_FADT->xgpe0_blk, register_count0, 0, + acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( @@ -1094,8 +1132,9 @@ acpi_ev_gpe_initialize ( else { /* Install GPE Block 1 */ - status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk, - register_count1, acpi_gbl_FADT->gpe1_base, + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, + &acpi_gbl_FADT->xgpe1_blk, register_count1, + acpi_gbl_FADT->gpe1_base, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]); if (ACPI_FAILURE (status)) { @@ -1109,7 +1148,7 @@ acpi_ev_gpe_initialize ( * space. However, GPE0 always starts at GPE number zero. */ gpe_number_max = acpi_gbl_FADT->gpe1_base + - ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); } } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 2548efa7a45..659e9095611 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -50,6 +50,35 @@ ACPI_MODULE_NAME ("evmisc") +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_notify_value_names[] = +{ + "Bus Check", + "Device Check", + "Device Wake", + "Eject request", + "Device Check Light", + "Frequency Mismatch", + "Bus Mode Mismatch", + "Power Fault" +}; +#endif + +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +acpi_ev_notify_dispatch ( + void *context); + +static void ACPI_SYSTEM_XFACE +acpi_ev_global_lock_thread ( + void *context); + +static u32 +acpi_ev_global_lock_handler ( + void *context); + + /******************************************************************************* * * FUNCTION: acpi_ev_is_notify_object @@ -98,20 +127,6 @@ acpi_ev_is_notify_object ( * ******************************************************************************/ -#ifdef ACPI_DEBUG_OUTPUT -static const char *acpi_notify_value_names[] = -{ - "Bus Check", - "Device Check", - "Device Wake", - "Eject request", - "Device Check Light", - "Frequency Mismatch", - "Bus Mode Mismatch", - "Power Fault" -}; -#endif - acpi_status acpi_ev_queue_notify_request ( struct acpi_namespace_node *node, @@ -128,9 +143,10 @@ acpi_ev_queue_notify_request ( /* * For value 3 (Ejection Request), some device method may need to be run. - * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run. + * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need + * to be run. * For value 0x80 (Status Change) on the power button or sleep button, - * initiate soft-off or sleep operation? + * initiate soft-off or sleep operation? */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dispatching Notify(%X) on node %p\n", notify_value, node)); @@ -140,8 +156,9 @@ acpi_ev_queue_notify_request ( acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", - notify_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Notify value: 0x%2.2X **Device Specific**\n", + notify_value)); } /* Get the notify object attached to the NS Node */ @@ -210,7 +227,7 @@ acpi_ev_queue_notify_request ( * * FUNCTION: acpi_ev_notify_dispatch * - * PARAMETERS: Context - To be passsed to the notify handler + * PARAMETERS: Context - To be passed to the notify handler * * RETURN: None. * @@ -219,7 +236,7 @@ acpi_ev_queue_notify_request ( * ******************************************************************************/ -void ACPI_SYSTEM_XFACE +static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch ( void *context) { @@ -234,7 +251,8 @@ acpi_ev_notify_dispatch ( /* * We will invoke a global notify handler if installed. - * This is done _before_ we invoke the per-device handler attached to the device. + * This is done _before_ we invoke the per-device handler attached + * to the device. */ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { /* Global system notification handler */ @@ -256,15 +274,17 @@ acpi_ev_notify_dispatch ( /* Invoke the system handler first, if present */ if (global_handler) { - global_handler (notify_info->notify.node, notify_info->notify.value, global_context); + global_handler (notify_info->notify.node, notify_info->notify.value, + global_context); } /* Now invoke the per-device handler, if present */ handler_obj = notify_info->notify.handler_obj; if (handler_obj) { - handler_obj->notify.handler (notify_info->notify.node, notify_info->notify.value, - handler_obj->notify.context); + handler_obj->notify.handler (notify_info->notify.node, + notify_info->notify.value, + handler_obj->notify.context); } /* All done with the info object */ @@ -370,7 +390,8 @@ acpi_ev_global_lock_handler ( ******************************************************************************/ acpi_status -acpi_ev_init_global_lock_handler (void) +acpi_ev_init_global_lock_handler ( + void) { acpi_status status; @@ -380,7 +401,7 @@ acpi_ev_init_global_lock_handler (void) acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL, - acpi_ev_global_lock_handler, NULL); + acpi_ev_global_lock_handler, NULL); /* * If the global lock does not exist on this platform, the attempt @@ -433,8 +454,10 @@ acpi_ev_acquire_global_lock ( acpi_gbl_global_lock_thread_count++; - /* If we (OS side vs. BIOS side) have the hardware lock already, we are done */ - + /* + * If we (OS side vs. BIOS side) have the hardware lock already, + * we are done + */ if (acpi_gbl_global_lock_acquired) { return_ACPI_STATUS (AE_OK); } @@ -480,7 +503,8 @@ acpi_ev_acquire_global_lock ( ******************************************************************************/ acpi_status -acpi_ev_release_global_lock (void) +acpi_ev_release_global_lock ( + void) { u8 pending = FALSE; acpi_status status = AE_OK; @@ -490,7 +514,8 @@ acpi_ev_release_global_lock (void) if (!acpi_gbl_global_lock_thread_count) { - ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n")); + ACPI_REPORT_WARNING(( + "Cannot release HW Global Lock, it has not been acquired\n")); return_ACPI_STATUS (AE_NOT_ACQUIRED); } @@ -515,7 +540,8 @@ acpi_ev_release_global_lock (void) * register */ if (pending) { - status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1, ACPI_MTX_LOCK); + status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, + 1, ACPI_MTX_LOCK); } return_ACPI_STATUS (status); @@ -535,7 +561,8 @@ acpi_ev_release_global_lock (void) ******************************************************************************/ void -acpi_ev_terminate (void) +acpi_ev_terminate ( + void) { acpi_native_uint i; acpi_status status; @@ -555,7 +582,8 @@ acpi_ev_terminate (void) for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { status = acpi_disable_event ((u32) i, 0); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable fixed event %d\n", (u32) i)); } } @@ -567,7 +595,8 @@ acpi_ev_terminate (void) status = acpi_ev_remove_sci_handler (); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not remove SCI handler\n")); } } diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 772342708a7..a1d7276c574 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -58,6 +58,22 @@ static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPA ACPI_ADR_SPACE_PCI_CONFIG, ACPI_ADR_SPACE_DATA_TABLE}; +/* Local prototypes */ + +static acpi_status +acpi_ev_reg_run ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + +static acpi_status +acpi_ev_install_handler ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + /******************************************************************************* * @@ -179,8 +195,8 @@ acpi_ev_initialize_op_regions ( * * FUNCTION: acpi_ev_execute_reg_method * - * PARAMETERS: region_obj - Object structure - * Function - Passed to _REG: On (1) or Off (0) + * PARAMETERS: region_obj - Region object + * Function - Passed to _REG: On (1) or Off (0) * * RETURN: Status * @@ -323,14 +339,16 @@ acpi_ev_address_space_dispatch ( if (!region_setup) { /* No initialization routine, exit with error */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No init routine for region(%p) [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No init routine for region(%p) [%s]\n", region_obj, acpi_ut_get_region_name (region_obj->region.space_id))); return_ACPI_STATUS (AE_NOT_EXIST); } /* - * We must exit the interpreter because the region setup will potentially - * execute control methods (e.g., _REG method for this region) + * We must exit the interpreter because the region + * setup will potentially execute control methods + * (e.g., _REG method for this region) */ acpi_ex_exit_interpreter (); @@ -621,7 +639,7 @@ acpi_ev_attach_region ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_install_handler ( acpi_handle obj_handle, u32 level, @@ -848,7 +866,8 @@ acpi_ev_install_space_handler ( if (handler_obj->address_space.handler == handler) { /* * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with PCI_Config space. + * handler twice. This can easily happen + * with PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; @@ -1011,7 +1030,7 @@ acpi_ev_execute_reg_methods ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_reg_run ( acpi_handle obj_handle, u32 level, diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 4983a3378be..95bc09c73a6 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -61,7 +61,7 @@ * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling, a nop for now + * DESCRIPTION: Setup a system_memory operation region * ******************************************************************************/ @@ -115,7 +115,7 @@ acpi_ev_system_memory_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a IO operation region * ******************************************************************************/ @@ -144,14 +144,14 @@ acpi_ev_io_space_region_setup ( * * FUNCTION: acpi_ev_pci_config_region_setup * - * PARAMETERS: Handle - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a PCI_Config operation region * * MUTEX: Assumes namespace is not locked * @@ -324,7 +324,7 @@ acpi_ev_pci_config_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a pci_bAR operation region * * MUTEX: Assumes namespace is not locked * @@ -355,7 +355,7 @@ acpi_ev_pci_bar_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a CMOS operation region * * MUTEX: Assumes namespace is not locked * @@ -386,7 +386,7 @@ acpi_ev_cmos_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Default region initialization * ******************************************************************************/ diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 46b31995c82..f3123c26ae9 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -49,6 +49,12 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evsci") +/* Local prototypes */ + +static u32 ACPI_SYSTEM_XFACE +acpi_ev_sci_xrupt_handler ( + void *context); + /******************************************************************************* * @@ -146,7 +152,8 @@ acpi_ev_gpe_xrupt_handler ( ******************************************************************************/ u32 -acpi_ev_install_sci_handler (void) +acpi_ev_install_sci_handler ( + void) { u32 status = AE_OK; @@ -180,7 +187,8 @@ acpi_ev_install_sci_handler (void) ******************************************************************************/ acpi_status -acpi_ev_remove_sci_handler (void) +acpi_ev_remove_sci_handler ( + void) { acpi_status status; diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 0bfec10a5f1..4092d47f675 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -64,6 +64,7 @@ * DESCRIPTION: Saves the pointer to the handler function * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_exception_handler ( @@ -457,7 +458,8 @@ acpi_remove_notify_handler ( /* Root Object */ if (device == ACPI_ROOT_OBJECT) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Removing notify handler for ROOT object.\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || @@ -564,8 +566,9 @@ EXPORT_SYMBOL(acpi_remove_notify_handler); * * FUNCTION: acpi_install_gpe_handler * - * PARAMETERS: gpe_number - The GPE number within the GPE block - * gpe_block - GPE block (NULL == FADT GPEs) + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. * Address - Address of the handler @@ -662,8 +665,9 @@ EXPORT_SYMBOL(acpi_install_gpe_handler); * * FUNCTION: acpi_remove_gpe_handler * - * PARAMETERS: gpe_number - The event to remove a handler - * gpe_block - GPE block (NULL == FADT GPEs) + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The event to remove a handler * Address - Address of the handler * * RETURN: Status @@ -766,7 +770,8 @@ EXPORT_SYMBOL(acpi_remove_gpe_handler); * FUNCTION: acpi_acquire_global_lock * * PARAMETERS: Timeout - How long the caller is willing to wait - * out_handle - A handle to the lock if acquired + * Handle - Where the handle to the lock is returned + * (if acquired) * * RETURN: Status * @@ -812,7 +817,7 @@ EXPORT_SYMBOL(acpi_acquire_global_lock); * * RETURN: Status * - * DESCRIPTION: Release the ACPI Global Lock + * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid. * ******************************************************************************/ diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index fa8d5f25be6..f337dc2cc56 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -64,7 +64,8 @@ ******************************************************************************/ acpi_status -acpi_enable (void) +acpi_enable ( + void) { acpi_status status = AE_OK; @@ -91,7 +92,8 @@ acpi_enable (void) return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Transition to ACPI mode successful\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Transition to ACPI mode successful\n")); } return_ACPI_STATUS (status); @@ -106,12 +108,13 @@ acpi_enable (void) * * RETURN: Status * - * DESCRIPTION: Transfers the system into LEGACY mode. + * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode. * ******************************************************************************/ acpi_status -acpi_disable (void) +acpi_disable ( + void) { acpi_status status = AE_OK; @@ -125,7 +128,8 @@ acpi_disable (void) } if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) { - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "System is already in legacy (non-ACPI) mode\n")); } else { /* Transition to LEGACY mode */ @@ -133,7 +137,8 @@ acpi_disable (void) status = acpi_hw_set_mode (ACPI_SYS_MODE_LEGACY); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not exit ACPI mode to legacy mode")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not exit ACPI mode to legacy mode")); return_ACPI_STATUS (status); } @@ -214,7 +219,7 @@ EXPORT_SYMBOL(acpi_enable_event); * * RETURN: Status * - * DESCRIPTION: Enable an ACPI event (general purpose) + * DESCRIPTION: Set the type of an individual GPE * ******************************************************************************/ @@ -519,13 +524,12 @@ unlock_and_exit: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_get_event_status * * PARAMETERS: Event - The fixed event - * Event Status - Where the current status of the event will + * event_status - Where the current status of the event will * be returned * * RETURN: Status @@ -571,7 +575,7 @@ acpi_get_event_status ( * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block * Flags - Called from an ISR or not - * Event Status - Where the current status of the event will + * event_status - Where the current status of the event will * be returned * * RETURN: Status @@ -775,4 +779,5 @@ unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } + EXPORT_SYMBOL(acpi_remove_gpe_block); diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index ac3c061967f..734b2f24af4 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -54,6 +54,14 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exconfig") +/* Local prototypes */ + +static acpi_status +acpi_ex_add_table ( + struct acpi_table_header *table, + struct acpi_namespace_node *parent_node, + union acpi_operand_object **ddb_handle); + /******************************************************************************* * @@ -70,7 +78,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_add_table ( struct acpi_table_header *table, struct acpi_namespace_node *parent_node, @@ -95,10 +103,10 @@ acpi_ex_add_table ( ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc)); - table_info.type = ACPI_TABLE_SSDT; - table_info.pointer = table; - table_info.length = (acpi_size) table->length; - table_info.allocation = ACPI_MEM_ALLOCATED; + table_info.type = ACPI_TABLE_SSDT; + table_info.pointer = table; + table_info.length = (acpi_size) table->length; + table_info.allocation = ACPI_MEM_ALLOCATED; status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { @@ -226,11 +234,10 @@ acpi_ex_load_table_op ( start_node = parent_node; } - /* - * Find the node referenced by the parameter_path_string - */ + /* Find the node referenced by the parameter_path_string */ + status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node, - ACPI_NS_SEARCH_PARENT, ¶meter_node); + ACPI_NS_SEARCH_PARENT, ¶meter_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -248,7 +255,8 @@ acpi_ex_load_table_op ( if (parameter_node) { /* Store the parameter data into the optional parameter object */ - status = acpi_ex_store (operand[5], ACPI_CAST_PTR (union acpi_operand_object, parameter_node), + status = acpi_ex_store (operand[5], + ACPI_CAST_PTR (union acpi_operand_object, parameter_node), walk_state); if (ACPI_FAILURE (status)) { (void) acpi_ex_unload_table (ddb_handle); @@ -371,7 +379,8 @@ acpi_ex_load_op ( goto cleanup; } - table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + table_ptr = ACPI_CAST_PTR (struct acpi_table_header, + buffer_desc->buffer.pointer); /* Sanity check the table length */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index df7ba1219bf..97856c48bd7 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -50,6 +50,15 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exconvrt") +/* Local prototypes */ + +static u32 +acpi_ex_convert_to_ascii ( + acpi_integer integer, + u16 base, + u8 *string, + u8 max_length); + /******************************************************************************* * @@ -115,9 +124,8 @@ acpi_ex_convert_to_integer ( */ result = 0; - /* - * String conversion is different than Buffer conversion - */ + /* String conversion is different than Buffer conversion */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_STRING: @@ -168,9 +176,8 @@ acpi_ex_convert_to_integer ( break; } - /* - * Create a new integer - */ + /* Create a new integer */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); @@ -251,7 +258,8 @@ acpi_ex_convert_to_buffer ( * ASL/AML code that depends on the null being transferred to the new * buffer. */ - return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length + 1); + return_desc = acpi_ut_create_buffer_object ( + (acpi_size) obj_desc->string.length + 1); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -291,7 +299,7 @@ acpi_ex_convert_to_buffer ( * ******************************************************************************/ -u32 +static u32 acpi_ex_convert_to_ascii ( acpi_integer integer, u16 base, @@ -357,8 +365,9 @@ acpi_ex_convert_to_ascii ( case 16: - hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */ + /* hex_length: 2 ascii hex chars per data byte */ + hex_length = ACPI_MUL_2 (data_width); for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) { /* Get one hex digit, most significant digits first */ @@ -475,7 +484,7 @@ acpi_ex_convert_to_string ( /* Setup string length, base, and separator */ switch (type) { - case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */ + case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string */ /* * From ACPI: "If Data is a buffer, it is converted to a string of * decimal values separated by commas." @@ -509,7 +518,7 @@ acpi_ex_convert_to_string ( string_length = (obj_desc->buffer.length * 3); break; - case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string operator */ + case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string */ /* * From ACPI: "If Data is a buffer, it is converted to a string of * hexadecimal values separated by commas." @@ -530,9 +539,8 @@ acpi_ex_convert_to_string ( return_ACPI_STATUS (AE_AML_STRING_LIMIT); } - /* - * Create a new string object and string buffer - */ + /* Create a new string object and string buffer */ + return_desc = acpi_ut_create_string_object ((acpi_size) string_length); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); @@ -551,8 +559,10 @@ acpi_ex_convert_to_string ( *new_buf++ = separator; /* each separated by a comma or space */ } - /* Null terminate the string (overwrites final comma/space from above) */ - + /* + * Null terminate the string + * (overwrites final comma/space from above) + */ new_buf--; *new_buf = 0; break; @@ -645,7 +655,6 @@ acpi_ex_convert_to_target_type ( case ACPI_TYPE_STRING: - /* * The operand must be a String. We can convert an * Integer or Buffer if necessary @@ -656,7 +665,6 @@ acpi_ex_convert_to_target_type ( case ACPI_TYPE_BUFFER: - /* * The operand must be a Buffer. We can convert an * Integer or String if necessary diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index d94c260dac6..812cdcb2e37 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -55,7 +55,7 @@ #ifndef ACPI_NO_METHOD_EXECUTION -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_alias * @@ -65,7 +65,7 @@ * * DESCRIPTION: Create a new named alias * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_alias ( @@ -140,8 +140,7 @@ acpi_ex_create_alias ( * target node or the alias Node */ status = acpi_ns_attach_object (alias_node, - acpi_ns_get_attached_object (target_node), - target_node->type); + acpi_ns_get_attached_object (target_node), target_node->type); break; } @@ -151,7 +150,7 @@ acpi_ex_create_alias ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_event * @@ -161,7 +160,7 @@ acpi_ex_create_alias ( * * DESCRIPTION: Create a new event object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_event ( @@ -185,7 +184,7 @@ acpi_ex_create_event ( * that the event is created in an unsignalled state */ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, - &obj_desc->event.semaphore); + &obj_desc->event.semaphore); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -193,7 +192,7 @@ acpi_ex_create_event ( /* Attach object to the Node */ status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0], - obj_desc, ACPI_TYPE_EVENT); + obj_desc, ACPI_TYPE_EVENT); cleanup: /* @@ -205,7 +204,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_mutex * @@ -217,7 +216,7 @@ cleanup: * * Mutex (Name[0], sync_level[1]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_mutex ( @@ -267,20 +266,20 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_region * * PARAMETERS: aml_start - Pointer to the region declaration AML * aml_length - Max length of the declaration AML - * Operands - List of operands for the opcode + * region_space - space_iD for the region * walk_state - Current state * * RETURN: Status * * DESCRIPTION: Create a new operation region object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_region ( @@ -321,7 +320,7 @@ acpi_ex_create_region ( } ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n", - acpi_ut_get_region_name (region_space), region_space)); + acpi_ut_get_region_name (region_space), region_space)); /* Create the region descriptor */ @@ -360,7 +359,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_table_region * @@ -370,7 +369,7 @@ cleanup: * * DESCRIPTION: Create a new data_table_region object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_table_region ( @@ -455,7 +454,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_processor * @@ -467,7 +466,7 @@ cleanup: * * Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_processor ( @@ -488,9 +487,8 @@ acpi_ex_create_processor ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Initialize the processor object from the operands - */ + /* Initialize the processor object from the operands */ + obj_desc->processor.proc_id = (u8) operand[1]->integer.value; obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value; obj_desc->processor.length = (u8) operand[3]->integer.value; @@ -507,7 +505,7 @@ acpi_ex_create_processor ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_power_resource * @@ -519,7 +517,7 @@ acpi_ex_create_processor ( * * power_resource (Name[0], system_level[1], resource_order[2]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_power_resource ( @@ -555,10 +553,10 @@ acpi_ex_create_power_resource ( acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } - #endif -/***************************************************************************** + +/******************************************************************************* * * FUNCTION: acpi_ex_create_method * @@ -570,7 +568,7 @@ acpi_ex_create_power_resource ( * * DESCRIPTION: Create a new method object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_method ( diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index e2f7c32f28d..40850064811 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -51,23 +51,48 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exdump") +/* Local prototypes */ + +#ifdef ACPI_FUTURE_USAGE +static void +acpi_ex_out_string ( + char *title, + char *value); + +static void +acpi_ex_out_pointer ( + char *title, + void *value); + +static void +acpi_ex_out_integer ( + char *title, + u32 value); + +static void +acpi_ex_out_address ( + char *title, + acpi_physical_address value); +#endif /* ACPI_FUTURE_USAGE */ + /* * The following routines are used for debug output only */ #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_operand * - * PARAMETERS: *obj_desc - Pointer to entry to be dumped + * PARAMETERS: *obj_desc - Pointer to entry to be dumped + * Depth - Current nesting depth * * RETURN: None * * DESCRIPTION: Dump an operand object * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_operand ( @@ -86,9 +111,8 @@ acpi_ex_dump_operand ( } if (!obj_desc) { - /* - * This could be a null element of a package - */ + /* This could be a null element of a package */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n")); return; } @@ -117,6 +141,8 @@ acpi_ex_dump_operand ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc)); } + /* Decode object type */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_LOCAL_REFERENCE: @@ -274,7 +300,9 @@ acpi_ex_dump_operand ( case ACPI_TYPE_STRING: acpi_os_printf ("String length %X @ %p ", - obj_desc->string.length, obj_desc->string.pointer); + obj_desc->string.length, + obj_desc->string.pointer); + acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX); acpi_os_printf ("\n"); break; @@ -290,10 +318,13 @@ acpi_ex_dump_operand ( acpi_os_printf ( "region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", - obj_desc->field.bit_length, obj_desc->field.access_byte_width, + obj_desc->field.bit_length, + obj_desc->field.access_byte_width, obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, - obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset); + obj_desc->field.base_byte_offset, + obj_desc->field.start_field_bit_offset); + acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1); break; @@ -308,13 +339,15 @@ acpi_ex_dump_operand ( acpi_os_printf ( "buffer_field: %X bits at byte %X bit %X of \n", - obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, + obj_desc->buffer_field.bit_length, + obj_desc->buffer_field.base_byte_offset, obj_desc->buffer_field.start_field_bit_offset); if (!obj_desc->buffer_field.buffer_obj) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n")); } - else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) { + else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != + ACPI_TYPE_BUFFER) { acpi_os_printf ("*not a Buffer* \n"); } else { @@ -331,10 +364,10 @@ acpi_ex_dump_operand ( case ACPI_TYPE_METHOD: - acpi_os_printf ( - "Method(%X) @ %p:%X\n", + acpi_os_printf ("Method(%X) @ %p:%X\n", obj_desc->method.param_count, - obj_desc->method.aml_start, obj_desc->method.aml_length); + obj_desc->method.aml_start, + obj_desc->method.aml_length); break; @@ -379,7 +412,7 @@ acpi_ex_dump_operand ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_operands * @@ -393,7 +426,7 @@ acpi_ex_dump_operand ( * * DESCRIPTION: Dump the object stack * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_operands ( @@ -441,10 +474,9 @@ acpi_ex_dump_operands ( #ifdef ACPI_FUTURE_USAGE - -/***************************************************************************** +/******************************************************************************* * - * FUNCTION: acpi_ex_out* + * FUNCTION: acpi_ex_out* functions * * PARAMETERS: Title - Descriptive text * Value - Value to be displayed @@ -453,9 +485,9 @@ acpi_ex_dump_operands ( * reduce the number of format strings required and keeps them * all in one place for easy modification. * - ****************************************************************************/ + ******************************************************************************/ -void +static void acpi_ex_out_string ( char *title, char *value) @@ -463,7 +495,7 @@ acpi_ex_out_string ( acpi_os_printf ("%20s : %s\n", title, value); } -void +static void acpi_ex_out_pointer ( char *title, void *value) @@ -471,7 +503,7 @@ acpi_ex_out_pointer ( acpi_os_printf ("%20s : %p\n", title, value); } -void +static void acpi_ex_out_integer ( char *title, u32 value) @@ -479,7 +511,7 @@ acpi_ex_out_integer ( acpi_os_printf ("%20s : %X\n", title, value); } -void +static void acpi_ex_out_address ( char *title, acpi_physical_address value) @@ -493,16 +525,16 @@ acpi_ex_out_address ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_node * * PARAMETERS: *Node - Descriptor to dump - * Flags - Force display + * Flags - Force display if TRUE * * DESCRIPTION: Dumps the members of the given.Node * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_node ( @@ -531,16 +563,16 @@ acpi_ex_dump_node ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_object_descriptor * * PARAMETERS: *Object - Descriptor to dump - * Flags - Force display + * Flags - Force display if TRUE * * DESCRIPTION: Dumps the members of the object descriptor given. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_object_descriptor ( @@ -553,6 +585,10 @@ acpi_ex_dump_object_descriptor ( ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor"); + if (!obj_desc) { + return_VOID; + } + if (!flags) { if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return_VOID; @@ -747,11 +783,17 @@ acpi_ex_dump_object_descriptor ( case ACPI_TYPE_LOCAL_REFERENCE: acpi_ex_out_integer ("target_type", obj_desc->reference.target_type); - acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name); + acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info ( + obj_desc->reference.opcode))->name); acpi_ex_out_integer ("Offset", obj_desc->reference.offset); acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object); acpi_ex_out_pointer ("Node", obj_desc->reference.node); acpi_ex_out_pointer ("Where", obj_desc->reference.where); + + if (obj_desc->reference.object) { + acpi_os_printf ("\nReferenced Object:\n"); + acpi_ex_dump_object_descriptor (obj_desc->reference.object, flags); + } break; @@ -788,6 +830,5 @@ acpi_ex_dump_object_descriptor ( } #endif /* ACPI_FUTURE_USAGE */ - #endif diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index be7f2124fa0..22c8fa480f6 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -120,8 +120,8 @@ acpi_ex_read_data_from_field ( * Note: Smbus protocol value is passed in upper 16-bits of Function */ status = acpi_ex_access_region (obj_desc, 0, - ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer), - ACPI_READ | (obj_desc->field.attribute << 16)); + ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer), + ACPI_READ | (obj_desc->field.attribute << 16)); acpi_ex_release_global_lock (locked); goto exit; } @@ -196,6 +196,7 @@ exit: * * PARAMETERS: source_desc - Contains data to write * obj_desc - The named field + * result_desc - Where the return value is returned, if any * * RETURN: Status * @@ -250,12 +251,15 @@ acpi_ex_write_data_to_field ( if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n", acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { - ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n", + ACPI_REPORT_ERROR (( + "SMBus write requires Buffer of length %X, found length %X\n", ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); } @@ -265,14 +269,16 @@ acpi_ex_write_data_to_field ( } buffer = buffer_desc->buffer.pointer; - ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); + ACPI_MEMCPY (buffer, source_desc->buffer.pointer, + ACPI_SMBUS_BUFFER_SIZE); /* Lock entire transaction if requested */ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* - * Perform the write (returns status and perhaps data in the same buffer) + * Perform the write (returns status and perhaps data in the + * same buffer) * Note: SMBus protocol type is passed in upper 16-bits of Function. */ status = acpi_ex_access_region (obj_desc, 0, @@ -284,9 +290,8 @@ acpi_ex_write_data_to_field ( return_ACPI_STATUS (status); } - /* - * Get a pointer to the data to be written - */ + /* Get a pointer to the data to be written */ + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; @@ -314,7 +319,8 @@ acpi_ex_write_data_to_field ( * the ACPI specification. */ new_buffer = NULL; - required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); + required_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); if (length < required_length) { /* We need to create a new buffer */ @@ -338,6 +344,7 @@ acpi_ex_write_data_to_field ( "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n", source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)), ACPI_GET_OBJECT_TYPE (source_desc), buffer, length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n", obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)), diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 9d0f9d2e906..3c2f89e00f7 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -52,12 +52,31 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exfldio") +/* Local prototypes */ + +static acpi_status +acpi_ex_field_datum_io ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write); + +static u8 +acpi_ex_register_overflow ( + union acpi_operand_object *obj_desc, + acpi_integer value); + +static acpi_status +acpi_ex_setup_region ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset); + /******************************************************************************* * * FUNCTION: acpi_ex_setup_region * - * PARAMETERS: *obj_desc - Field to be read or written + * PARAMETERS: obj_desc - Field to be read or written * field_datum_byte_offset - Byte offset of this datum within the * parent field * @@ -69,7 +88,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_setup_region ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset) @@ -127,9 +146,9 @@ acpi_ex_setup_region ( * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ - if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset - + field_datum_byte_offset - + obj_desc->common_field.access_byte_width)) { + if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + + field_datum_byte_offset + + obj_desc->common_field.access_byte_width)) { if (acpi_gbl_enable_interpreter_slack) { /* * Slack mode only: We will go ahead and allow access to this @@ -155,7 +174,8 @@ acpi_ex_setup_region ( "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.access_byte_width, - acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + acpi_ut_get_node_name (rgn_desc->region.node), + rgn_desc->region.length)); } /* @@ -167,7 +187,8 @@ acpi_ex_setup_region ( acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, - acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + acpi_ut_get_node_name (rgn_desc->region.node), + rgn_desc->region.length)); return_ACPI_STATUS (AE_AML_REGION_LIMIT); } @@ -180,10 +201,10 @@ acpi_ex_setup_region ( * * FUNCTION: acpi_ex_access_region * - * PARAMETERS: *obj_desc - Field to be read + * PARAMETERS: obj_desc - Field to be read * field_datum_byte_offset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must at least + * Value - Where to store value (must at least * the size of acpi_integer) * Function - Read or Write flag plus other region- * dependent flags @@ -226,9 +247,9 @@ acpi_ex_access_region ( * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address - + obj_desc->common_field.base_byte_offset - + field_datum_byte_offset; + address = rgn_desc->region.address + + obj_desc->common_field.base_byte_offset + + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); @@ -249,7 +270,8 @@ acpi_ex_access_region ( /* Invoke the appropriate address_space/op_region handler */ status = acpi_ev_address_space_dispatch (rgn_desc, function, - address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); + address, + ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); if (ACPI_FAILURE (status)) { if (status == AE_NOT_IMPLEMENTED) { @@ -274,7 +296,7 @@ acpi_ex_access_region ( * * FUNCTION: acpi_ex_register_overflow * - * PARAMETERS: *obj_desc - Register(Field) to be written + * PARAMETERS: obj_desc - Register(Field) to be written * Value - Value to be stored * * RETURN: TRUE if value overflows the field, FALSE otherwise @@ -287,7 +309,7 @@ acpi_ex_access_region ( * ******************************************************************************/ -u8 +static u8 acpi_ex_register_overflow ( union acpi_operand_object *obj_desc, acpi_integer value) @@ -319,10 +341,10 @@ acpi_ex_register_overflow ( * * FUNCTION: acpi_ex_field_datum_io * - * PARAMETERS: *obj_desc - Field to be read + * PARAMETERS: obj_desc - Field to be read * field_datum_byte_offset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must be 64 bits) + * Value - Where to store value (must be 64 bits) * read_write - Read or Write flag * * RETURN: Status @@ -333,7 +355,7 @@ acpi_ex_register_overflow ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_field_datum_io ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, @@ -350,7 +372,9 @@ acpi_ex_field_datum_io ( if (read_write == ACPI_READ) { if (!value) { local_value = 0; - value = &local_value; /* To support reads without saving return value */ + + /* To support reads without saving return value */ + value = &local_value; } /* Clear the entire return buffer first, [Very Important!] */ @@ -363,8 +387,10 @@ acpi_ex_field_datum_io ( * * buffer_field - Read/write from/to a Buffer * region_field - Read/write from/to a Operation Region. - * bank_field - Write to a Bank Register, then read/write from/to an op_region - * index_field - Write to an Index Register, then read/write from/to a Data Register + * bank_field - Write to a Bank Register, then read/write from/to an + * operation_region + * index_field - Write to an Index Register, then read/write from/to a + * Data Register */ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_BUFFER_FIELD: @@ -384,19 +410,20 @@ acpi_ex_field_datum_io ( * Copy the data from the source buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset - + field_datum_byte_offset, - obj_desc->common_field.access_byte_width); + ACPI_MEMCPY (value, + (obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset - + field_datum_byte_offset, + ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, value, obj_desc->common_field.access_byte_width); } @@ -406,8 +433,10 @@ acpi_ex_field_datum_io ( case ACPI_TYPE_LOCAL_BANK_FIELD: - /* Ensure that the bank_value is not beyond the capacity of the register */ - + /* + * Ensure that the bank_value is not beyond the capacity of + * the register + */ if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, (acpi_integer) obj_desc->bank_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); @@ -445,8 +474,10 @@ acpi_ex_field_datum_io ( case ACPI_TYPE_LOCAL_INDEX_FIELD: - /* Ensure that the index_value is not beyond the capacity of the register */ - + /* + * Ensure that the index_value is not beyond the capacity of + * the register + */ if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, (acpi_integer) obj_desc->index_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); @@ -496,14 +527,16 @@ acpi_ex_field_datum_io ( if (ACPI_SUCCESS (status)) { if (read_write == ACPI_READ) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*value), - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Read %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*value), - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Written %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); } } @@ -515,8 +548,10 @@ acpi_ex_field_datum_io ( * * FUNCTION: acpi_ex_write_with_update_rule * - * PARAMETERS: *obj_desc - Field to be set - * Value - Value to store + * PARAMETERS: obj_desc - Field to be written + * Mask - bitmask within field datum + * field_value - Value to write + * field_datum_byte_offset - Offset of datum within field * * RETURN: Status * @@ -689,7 +724,8 @@ acpi_ex_extract_from_field ( /* Merge with previous datum if necessary */ merged_datum |= raw_datum << - (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + (obj_desc->common_field.access_bit_width - + obj_desc->common_field.start_field_bit_offset); if (i == datum_count) { break; @@ -707,7 +743,8 @@ acpi_ex_extract_from_field ( /* Mask off any extra bits in the last datum */ - buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; + buffer_tail_bits = obj_desc->common_field.bit_length % + obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } @@ -791,7 +828,8 @@ acpi_ex_insert_into_field ( /* Write merged datum to the target field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + status = acpi_ex_write_with_update_rule (obj_desc, mask, + merged_datum, field_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -800,7 +838,8 @@ acpi_ex_insert_into_field ( field_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> - (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + (obj_desc->common_field.access_bit_width - + obj_desc->common_field.start_field_bit_offset); mask = ACPI_INTEGER_MAX; if (i == datum_count) { @@ -819,7 +858,8 @@ acpi_ex_insert_into_field ( /* Mask off any extra bits in the last datum */ buffer_tail_bits = (obj_desc->common_field.bit_length + - obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; + obj_desc->common_field.start_field_bit_offset) % + obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } @@ -827,7 +867,8 @@ acpi_ex_insert_into_field ( /* Write the last datum to the field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + status = acpi_ex_write_with_update_rule (obj_desc, + mask, merged_datum, field_offset); return_ACPI_STATUS (status); } diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index b542dcd58c0..022f281345b 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -139,8 +139,9 @@ acpi_ex_get_object_reference ( reference_obj->reference.object = referenced_obj; *return_desc = reference_obj; - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n", - obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Object %p Type [%s], returning Reference %p\n", + obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); return_ACPI_STATUS (AE_OK); } @@ -456,7 +457,7 @@ acpi_ex_do_math_op ( return (integer0 * integer1); - case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */ + case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result)*/ return (integer0 << integer1); diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 68c4bb1970a..c3cb714d2cb 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -49,6 +49,13 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exmutex") +/* Local prototypes */ + +static void +acpi_ex_link_mutex ( + union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread); + /******************************************************************************* * @@ -56,7 +63,7 @@ * * PARAMETERS: obj_desc - The mutex to be unlinked * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Remove a mutex from the "acquired_mutex" list * @@ -92,16 +99,16 @@ acpi_ex_unlink_mutex ( * * FUNCTION: acpi_ex_link_mutex * - * PARAMETERS: obj_desc - The mutex to be linked - * list_head - head of the "acquired_mutex" list + * PARAMETERS: obj_desc - The mutex to be linked + * Thread - Current executing thread object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk * ******************************************************************************/ -void +static void acpi_ex_link_mutex ( union acpi_operand_object *obj_desc, struct acpi_thread_state *thread) @@ -132,8 +139,9 @@ acpi_ex_link_mutex ( * * FUNCTION: acpi_ex_acquire_mutex * - * PARAMETERS: time_desc - The 'time to delay' object descriptor - * obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - Timeout integer + * obj_desc - Mutex object + * walk_state - Current method execution state * * RETURN: Status * @@ -161,7 +169,7 @@ acpi_ex_acquire_mutex ( if (!walk_state->thread) { ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -170,8 +178,9 @@ acpi_ex_acquire_mutex ( * mutex. This mechanism provides some deadlock prevention */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { - ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + ACPI_REPORT_ERROR (( + "Cannot acquire Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -180,8 +189,10 @@ acpi_ex_acquire_mutex ( if (obj_desc->mutex.owner_thread) { /* Special case for Global Lock, allow all threads */ - if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) || - (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) { + if ((obj_desc->mutex.owner_thread->thread_id == + walk_state->thread->thread_id) || + (obj_desc->mutex.semaphore == + acpi_gbl_global_lock_semaphore)) { /* * The mutex is already owned by this thread, * just increment the acquisition depth @@ -221,6 +232,7 @@ acpi_ex_acquire_mutex ( * FUNCTION: acpi_ex_release_mutex * * PARAMETERS: obj_desc - The object descriptor for this op + * walk_state - Current method execution state * * RETURN: Status * @@ -278,8 +290,9 @@ acpi_ex_release_mutex ( * equal to the current sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { - ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + ACPI_REPORT_ERROR (( + "Cannot release Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -313,11 +326,11 @@ acpi_ex_release_mutex ( * * FUNCTION: acpi_ex_release_all_mutexes * - * PARAMETERS: mutex_list - Head of the mutex list + * PARAMETERS: Thread - Current executing thread object * * RETURN: Status * - * DESCRIPTION: Release all mutexes in the list + * DESCRIPTION: Release all mutexes held by this thread * ******************************************************************************/ diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 7911c533c26..639f0bd3f6d 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -50,13 +50,17 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exnames") +/* Local prototypes */ -/* AML Package Length encodings */ +static char * +acpi_ex_allocate_name_string ( + u32 prefix_count, + u32 num_name_segs); -#define ACPI_AML_PACKAGE_TYPE1 0x40 -#define ACPI_AML_PACKAGE_TYPE2 0x4000 -#define ACPI_AML_PACKAGE_TYPE3 0x400000 -#define ACPI_AML_PACKAGE_TYPE4 0x40000000 +static acpi_status +acpi_ex_name_segment ( + u8 **in_aml_address, + char *name_string); /******************************************************************************* @@ -64,7 +68,7 @@ * FUNCTION: acpi_ex_allocate_name_string * * PARAMETERS: prefix_count - Count of parent levels. Special cases: - * (-1) = root, 0 = none + * (-1)==root, 0==none * num_name_segs - count of 4-character name segments * * RETURN: A pointer to the allocated string segment. This segment must @@ -75,7 +79,7 @@ * ******************************************************************************/ -char * +static char * acpi_ex_allocate_name_string ( u32 prefix_count, u32 num_name_segs) @@ -88,7 +92,7 @@ acpi_ex_allocate_name_string ( /* - * Allow room for all \ and ^ prefixes, all segments, and a multi_name_prefix. + * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix. * Also, one byte for the null terminator. * This may actually be somewhat longer than needed. */ @@ -107,7 +111,8 @@ acpi_ex_allocate_name_string ( */ name_string = ACPI_MEM_ALLOCATE (size_needed); if (!name_string) { - ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", size_needed)); + ACPI_REPORT_ERROR (( + "ex_allocate_name_string: Could not allocate size %d\n", size_needed)); return_PTR (NULL); } @@ -152,15 +157,17 @@ acpi_ex_allocate_name_string ( * * FUNCTION: acpi_ex_name_segment * - * PARAMETERS: interpreter_mode - Current running mode (load1/Load2/Exec) + * PARAMETERS: in_aml_address - Pointer to the name in the AML code + * name_string - Where to return the name. The name is appended + * to any existing string to form a namepath * * RETURN: Status * - * DESCRIPTION: Execute a name segment (4 bytes) + * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_name_segment ( u8 **in_aml_address, char *name_string) @@ -223,10 +230,13 @@ acpi_ex_name_segment ( status = AE_CTRL_PENDING; } else { - /* Segment started with one or more valid characters, but fewer than 4 */ - + /* + * Segment started with one or more valid characters, but fewer than + * the required 4 + */ status = AE_AML_BAD_NAME; - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Bad character %02x in name, at %p\n", *aml_address, aml_address)); } @@ -239,11 +249,16 @@ acpi_ex_name_segment ( * * FUNCTION: acpi_ex_get_name_string * - * PARAMETERS: data_type - Data type to be associated with this name + * PARAMETERS: data_type - Object type to be associated with this + * name + * in_aml_address - Pointer to the namestring in the AML code + * out_name_string - Where the namestring is returned + * out_name_length - Length of the returned string * - * RETURN: Status + * RETURN: Status, namestring and length * - * DESCRIPTION: Get a name, including any prefixes. + * DESCRIPTION: Extract a full namepath from the AML byte stream, + * including any prefixes. * ******************************************************************************/ @@ -286,7 +301,8 @@ acpi_ex_get_name_string ( switch (*aml_address) { case AML_ROOT_PREFIX: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", + aml_address)); /* * Remember that we have a root_prefix -- @@ -303,7 +319,8 @@ acpi_ex_get_name_string ( /* Increment past possibly multiple parent prefixes */ do { - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", + aml_address)); aml_address++; prefix_count++; @@ -321,13 +338,13 @@ acpi_ex_get_name_string ( break; } - /* Examine first character of name for name segment prefix operator */ switch (*aml_address) { case AML_DUAL_NAME_PREFIX: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", + aml_address)); aml_address++; name_string = acpi_ex_allocate_name_string (prefix_count, 2); @@ -349,7 +366,8 @@ acpi_ex_get_name_string ( case AML_MULTI_NAME_PREFIX_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", + aml_address)); /* Fetch count of segments remaining in name path */ @@ -368,7 +386,8 @@ acpi_ex_get_name_string ( has_prefix = TRUE; while (num_segments && - (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) { + (status = acpi_ex_name_segment (&aml_address, name_string)) == + AE_OK) { num_segments--; } @@ -380,7 +399,8 @@ acpi_ex_get_name_string ( /* null_name valid as of 8-12-98 ASL/AML Grammar Update */ if (prefix_count == ACPI_UINT32_MAX) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "name_seg is \"\\\" followed by NULL\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "name_seg is \"\\\" followed by NULL\n")); } /* Consume the NULL byte */ diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 8482aefaf38..dbdf8262ba0 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -97,7 +97,8 @@ acpi_ex_opcode_0A_0T_1R ( union acpi_operand_object *return_desc = NULL; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -161,7 +162,8 @@ acpi_ex_opcode_1A_0T_0R ( acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -236,7 +238,8 @@ acpi_ex_opcode_1A_1T_0R ( union acpi_operand_object **operand = &walk_state->operands[0]; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -289,7 +292,8 @@ acpi_ex_opcode_1A_1T_1R ( acpi_integer digit; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -409,8 +413,10 @@ acpi_ex_opcode_1A_1T_1R ( for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { (void) acpi_ut_short_divide (digit, 10, &digit, &temp32); - /* Insert the BCD digit that resides in the remainder from above */ - + /* + * Insert the BCD digit that resides in the + * remainder from above + */ return_desc->integer.value |= (((acpi_integer) temp32) << ACPI_MUL_4 (i)); } @@ -445,7 +451,8 @@ acpi_ex_opcode_1A_1T_1R ( /* Get the object reference, store it, and remove our reference */ - status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state); + status = acpi_ex_get_object_reference (operand[0], + &return_desc2, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -482,10 +489,10 @@ acpi_ex_opcode_1A_1T_1R ( if (!walk_state->result_obj) { /* - * Normally, we would remove a reference on the Operand[0] parameter; - * But since it is being used as the internal return object - * (meaning we would normally increment it), the two cancel out, - * and we simply don't do anything. + * Normally, we would remove a reference on the Operand[0] + * parameter; But since it is being used as the internal return + * object (meaning we would normally increment it), the two + * cancel out, and we simply don't do anything. */ walk_state->result_obj = operand[0]; walk_state->operands[0] = NULL; /* Prevent deletion */ @@ -549,9 +556,8 @@ acpi_ex_opcode_1A_1T_1R ( case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ - /* - * These are two obsolete opcodes - */ + /* These are two obsolete opcodes */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s is obsolete and not implemented\n", acpi_ps_get_opcode_name (walk_state->opcode))); @@ -568,9 +574,8 @@ acpi_ex_opcode_1A_1T_1R ( } if (ACPI_SUCCESS (status)) { - /* - * Store the return value computed above into the target object - */ + /* Store the return value computed above into the target object */ + status = acpi_ex_store (return_desc, operand[1], walk_state); } @@ -615,7 +620,8 @@ acpi_ex_opcode_1A_0T_1R ( acpi_integer value; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -706,9 +712,9 @@ acpi_ex_opcode_1A_0T_1R ( /* * Note: The operand is not resolved at this point because we want to - * get the associated object, not its value. For example, we don't want - * to resolve a field_unit to its value, we want the actual field_unit - * object. + * get the associated object, not its value. For example, we don't + * want to resolve a field_unit to its value, we want the actual + * field_unit object. */ /* Get the type of the base object */ @@ -738,7 +744,8 @@ acpi_ex_opcode_1A_0T_1R ( /* Get the base object */ - status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc); + status = acpi_ex_resolve_multiple (walk_state, + operand[0], &type, &temp_desc); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -818,8 +825,10 @@ acpi_ex_opcode_1A_0T_1R ( /* Set Operand[0] to the value of the local/arg */ - status = acpi_ds_method_data_get_value (operand[0]->reference.opcode, - operand[0]->reference.offset, walk_state, &temp_desc); + status = acpi_ds_method_data_get_value ( + operand[0]->reference.opcode, + operand[0]->reference.offset, + walk_state, &temp_desc); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -852,21 +861,26 @@ acpi_ex_opcode_1A_0T_1R ( case ACPI_TYPE_STRING: /* - * This is a deref_of (String). The string is a reference to a named ACPI object. + * This is a deref_of (String). The string is a reference + * to a named ACPI object. * * 1) Find the owning Node - * 2) Dereference the node to an actual object. Could be a Field, so we nee - * to resolve the node to a value. + * 2) Dereference the node to an actual object. Could be a + * Field, so we need to resolve the node to a value. */ status = acpi_ns_get_node_by_path (operand[0]->string.pointer, - walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT, - ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc)); + walk_state->scope_info->scope.node, + ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR ( + struct acpi_namespace_node, &return_desc)); if (ACPI_FAILURE (status)) { goto cleanup; } status = acpi_ex_resolve_node_to_value ( - ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc), walk_state); + ACPI_CAST_INDIRECT_PTR ( + struct acpi_namespace_node, &return_desc), + walk_state); goto cleanup; @@ -883,14 +897,16 @@ acpi_ex_opcode_1A_0T_1R ( /* * This is a deref_of (object_reference) * Get the actual object from the Node (This is the dereference). - * -- This case may only happen when a local_x or arg_x is dereferenced above. + * This case may only happen when a local_x or arg_x is + * dereferenced above. */ - return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) operand[0]); + return_desc = acpi_ns_get_attached_object ( + (struct acpi_namespace_node *) operand[0]); } else { /* - * This must be a reference object produced by either the Index() or - * ref_of() operator + * This must be a reference object produced by either the + * Index() or ref_of() operator */ switch (operand[0]->reference.opcode) { case AML_INDEX_OP: @@ -931,8 +947,8 @@ acpi_ex_opcode_1A_0T_1R ( case ACPI_TYPE_PACKAGE: /* - * Return the referenced element of the package. We must add - * another reference to the referenced object, however. + * Return the referenced element of the package. We must + * add another reference to the referenced object, however. */ return_desc = *(operand[0]->reference.where); if (!return_desc) { @@ -967,9 +983,11 @@ acpi_ex_opcode_1A_0T_1R ( return_desc = operand[0]->reference.object; - if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == + ACPI_DESC_TYPE_NAMED) { - return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) return_desc); + return_desc = acpi_ns_get_attached_object ( + (struct acpi_namespace_node *) return_desc); } /* Add another reference to the object! */ diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 8be4d80ceed..7429032c2b6 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -118,7 +118,7 @@ acpi_ex_opcode_2A_0T_0R ( value = (u32) operand[1]->integer.value; - /* Notifies allowed on this object? */ + /* Are notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -203,11 +203,12 @@ acpi_ex_opcode_2A_2T_1R ( acpi_ps_get_opcode_name (walk_state->opcode)); - /* - * Execute the opcode - */ + /* Execute the opcode */ + switch (walk_state->opcode) { - case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, remainder_result quotient_result) */ + case AML_DIVIDE_OP: + + /* Divide (Dividend, Divisor, remainder_result quotient_result) */ return_desc1 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc1) { @@ -241,7 +242,6 @@ acpi_ex_opcode_2A_2T_1R ( goto cleanup; } - /* Store the results to the target reference operands */ status = acpi_ex_store (return_desc2, operand[2], walk_state); @@ -295,7 +295,7 @@ acpi_ex_opcode_2A_1T_1R ( { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; - u32 index; + acpi_integer index; acpi_status status = AE_OK; acpi_size length; @@ -304,9 +304,8 @@ acpi_ex_opcode_2A_1T_1R ( acpi_ps_get_opcode_name (walk_state->opcode)); - /* - * Execute the opcode - */ + /* Execute the opcode */ + if (walk_state->op_info->flags & AML_MATH) { /* All simple math opcodes (add, etc.) */ @@ -322,9 +321,8 @@ acpi_ex_opcode_2A_1T_1R ( goto store_result_to_target; } - switch (walk_state->opcode) { - case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ + case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { @@ -341,18 +339,19 @@ acpi_ex_opcode_2A_1T_1R ( break; - case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ + case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ status = acpi_ex_do_concatenate (operand[0], operand[1], &return_desc, walk_state); break; - case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ + case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ /* * Input object is guaranteed to be a buffer at this point (it may have - * been converted.) Copy the raw buffer data to a new object of type String. + * been converted.) Copy the raw buffer data to a new object of + * type String. */ /* @@ -383,14 +382,16 @@ acpi_ex_opcode_2A_1T_1R ( goto cleanup; } - /* Copy the raw buffer data with no transform. NULL terminated already. */ + /* Copy the raw buffer data with no transform. NULL terminated already*/ ACPI_MEMCPY (return_desc->string.pointer, operand[0]->buffer.pointer, length); break; - case AML_CONCAT_RES_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ + case AML_CONCAT_RES_OP: + + /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ status = acpi_ex_concat_template (operand[0], operand[1], &return_desc, walk_state); @@ -407,33 +408,33 @@ acpi_ex_opcode_2A_1T_1R ( goto cleanup; } - index = (u32) operand[1]->integer.value; + index = operand[1]->integer.value; + + /* At this point, the Source operand is a Package, Buffer, or String */ - /* - * At this point, the Source operand is a Package, Buffer, or String - */ if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) { /* Object to be indexed is a Package */ if (index >= operand[0]->package.count) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index value (%X) beyond package end (%X)\n", - index, operand[0]->package.count)); + "Index value (%X%8.8X) beyond package end (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } return_desc->reference.target_type = ACPI_TYPE_PACKAGE; return_desc->reference.object = operand[0]; - return_desc->reference.where = &operand[0]->package.elements [index]; + return_desc->reference.where = &operand[0]->package.elements [ + index]; } else { /* Object to be indexed is a Buffer/String */ if (index >= operand[0]->buffer.length) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index value (%X) beyond end of buffer (%X)\n", - index, operand[0]->buffer.length)); + "Index value (%X%8.8X) beyond end of buffer (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } @@ -451,7 +452,7 @@ acpi_ex_opcode_2A_1T_1R ( /* Complete the Index reference object */ return_desc->reference.opcode = AML_INDEX_OP; - return_desc->reference.offset = index; + return_desc->reference.offset = (u32) index; /* Store the reference to the Target */ @@ -536,22 +537,24 @@ acpi_ex_opcode_2A_0T_1R ( goto cleanup; } - /* - * Execute the Opcode - */ - if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) /* logical_op (Operand0, Operand1) */ { + /* Execute the Opcode */ + + if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { + /* logical_op (Operand0, Operand1) */ + status = acpi_ex_do_logical_numeric_op (walk_state->opcode, operand[0]->integer.value, operand[1]->integer.value, &logical_result); goto store_logical_result; } - else if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + else if (walk_state->op_info->flags & AML_LOGICAL) { + /* logical_op (Operand0, Operand1) */ + status = acpi_ex_do_logical_op (walk_state->opcode, operand[0], operand[1], &logical_result); goto store_logical_result; } - switch (walk_state->opcode) { case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 29d0b167745..23b068adbf5 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -97,11 +97,12 @@ acpi_ex_opcode_3A_0T_0R ( acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { - case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ + case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", @@ -116,9 +117,8 @@ acpi_ex_opcode_3A_0T_0R ( fatal->argument = (u32) operand[2]->integer.value; } - /* - * Always signal the OS! - */ + /* Always signal the OS! */ + status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal); /* Might return while OS is shutting down, just continue */ @@ -162,21 +162,23 @@ acpi_ex_opcode_3A_1T_1R ( union acpi_operand_object *return_desc = NULL; char *buffer; acpi_status status = AE_OK; - acpi_native_uint index; + acpi_integer index; acpi_size length; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { - case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ + case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ - return_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (operand[0])); + return_desc = acpi_ut_create_internal_object ( + ACPI_GET_OBJECT_TYPE (operand[0])); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -184,7 +186,7 @@ acpi_ex_opcode_3A_1T_1R ( /* Get the Integer values from the objects */ - index = (acpi_native_uint) operand[1]->integer.value; + index = operand[1]->integer.value; length = (acpi_size) operand[2]->integer.value; /* @@ -197,7 +199,8 @@ acpi_ex_opcode_3A_1T_1R ( if ((index + length) > operand[0]->string.length) { - length = (acpi_size) operand[0]->string.length - index; + length = (acpi_size) operand[0]->string.length - + (acpi_size) index; } /* Allocate a new buffer for the String/Buffer */ diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index d3262433162..17f81d42ee4 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -75,6 +75,14 @@ * fully resolved operands. !*/ +/* Local prototypes */ + +static u8 +acpi_ex_do_match ( + u32 match_op, + union acpi_operand_object *package_obj, + union acpi_operand_object *match_obj); + /******************************************************************************* * @@ -92,7 +100,7 @@ * ******************************************************************************/ -u8 +static u8 acpi_ex_do_match ( u32 match_op, union acpi_operand_object *package_obj, @@ -216,11 +224,12 @@ acpi_ex_opcode_6A_0T_1R ( union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; - u32 index; + acpi_integer index; union acpi_operand_object *this_element; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { @@ -241,9 +250,11 @@ acpi_ex_opcode_6A_0T_1R ( /* Get the package start_index, validate against the package length */ - index = (u32) operand[5]->integer.value; - if (index >= (u32) operand[0]->package.count) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n")); + index = operand[5]->integer.value; + if (index >= operand[0]->package.count) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index (%X%8.8X) beyond package end (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } @@ -314,13 +325,12 @@ acpi_ex_opcode_6A_0T_1R ( default: - ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("acpi_ex_opcode_6A_0T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } - walk_state->result_obj = return_desc; diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 264ef3bba31..c9e3c68b554 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -52,8 +52,23 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exprep") +/* Local prototypes */ + +static u32 +acpi_ex_decode_field_access ( + union acpi_operand_object *obj_desc, + u8 field_flags, + u32 *return_byte_alignment); + #ifdef ACPI_UNDER_DEVELOPMENT + +static u32 +acpi_ex_generate_access ( + u32 field_bit_offset, + u32 field_bit_length, + u32 region_length); + /******************************************************************************* * * FUNCTION: acpi_ex_generate_access @@ -99,12 +114,14 @@ acpi_ex_generate_access ( /* Round Field start offset and length to "minimal" byte boundaries */ field_byte_offset = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8)); - field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8)); + field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + + field_bit_offset, 8)); field_byte_length = field_byte_end_offset - field_byte_offset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Bit length %d, Bit offset %d\n", field_bit_length, field_bit_offset)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Byte Length %d, Byte Offset %d, End Offset %d\n", field_byte_length, field_byte_offset, field_byte_end_offset)); @@ -117,20 +134,26 @@ acpi_ex_generate_access ( */ for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { /* - * 1) Round end offset up to next access boundary and make sure that this - * does not go beyond the end of the parent region. - * 2) When the Access width is greater than the field_byte_length, we are done. - * (This does not optimize for the perfectly aligned case yet). + * 1) Round end offset up to next access boundary and make sure that + * this does not go beyond the end of the parent region. + * 2) When the Access width is greater than the field_byte_length, we + * are done. (This does not optimize for the perfectly aligned + * case yet). */ if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) { - field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) / - access_byte_width; - field_end_offset = ACPI_ROUND_UP ((field_byte_length + field_byte_offset), - access_byte_width) / access_byte_width; - accesses = field_end_offset - field_start_offset; + field_start_offset = + ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) / + access_byte_width; + + field_end_offset = + ACPI_ROUND_UP ((field_byte_length + field_byte_offset), + access_byte_width) / access_byte_width; + + accesses = field_end_offset - field_start_offset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "access_width %d end is within region\n", access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field Start %d, Field End %d -- requires %d accesses\n", field_start_offset, field_end_offset, accesses)); @@ -139,8 +162,8 @@ acpi_ex_generate_access ( if (accesses <= 1) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Entire field can be accessed with one operation of size %d\n", - access_byte_width)); + "Entire field can be accessed with one operation of size %d\n", + access_byte_width)); return_VALUE (access_byte_width); } @@ -155,15 +178,20 @@ acpi_ex_generate_access ( } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "access_width %d end is NOT within region\n", access_byte_width)); + "access_width %d end is NOT within region\n", access_byte_width)); if (access_byte_width == 1) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field goes beyond end-of-region!\n")); - return_VALUE (0); /* Field does not fit in the region at all */ - } - /* This width goes beyond the end-of-region, back off to previous access */ + /* Field does not fit in the region at all */ + return_VALUE (0); + } + + /* + * This width goes beyond the end-of-region, back off to + * previous access + */ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Backing off to previous optimal access width of %d\n", minimum_access_width)); @@ -171,8 +199,10 @@ acpi_ex_generate_access ( } } - /* Could not read/write field with one operation, just use max access width */ - + /* + * Could not read/write field with one operation, + * just use max access width + */ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); return_VALUE (8); @@ -184,8 +214,9 @@ acpi_ex_generate_access ( * * FUNCTION: acpi_ex_decode_field_access * - * PARAMETERS: Access - Encoded field access bits - * Length - Field length. + * PARAMETERS: obj_desc - Field object + * field_flags - Encoded fieldflags (contains access bits) + * return_byte_alignment - Where the byte alignment is returned * * RETURN: Field granularity (8, 16, 32 or 64) and * byte_alignment (1, 2, 3, or 4) @@ -214,9 +245,10 @@ acpi_ex_decode_field_access ( case AML_FIELD_ACCESS_ANY: #ifdef ACPI_UNDER_DEVELOPMENT - byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset, - obj_desc->common_field.bit_length, - 0xFFFFFFFF /* Temp until we pass region_length as param */); + byte_alignment = + acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.bit_length, + 0xFFFFFFFF /* Temp until we pass region_length as parameter */); bit_length = byte_alignment * 8; #endif @@ -276,6 +308,7 @@ acpi_ex_decode_field_access ( * field_flags - Access, lock_rule, and update_rule. * The format of a field_flag is described * in the ACPI specification + * field_attribute - Special attributes (not used) * field_bit_position - Field start position * field_bit_length - Field length in number of bits * @@ -337,7 +370,7 @@ acpi_ex_prep_common_field_object ( /* Setup width (access granularity) fields */ obj_desc->common_field.access_byte_width = (u8) - ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ + ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ obj_desc->common_field.access_bit_width = (u8) access_bit_width; @@ -380,11 +413,7 @@ acpi_ex_prep_common_field_object ( * * FUNCTION: acpi_ex_prep_field_value * - * PARAMETERS: Node - Owning Node - * region_node - Region in which field is being defined - * field_flags - Access, lock_rule, and update_rule. - * field_bit_position - Field start position - * field_bit_length - Field length in number of bits + * PARAMETERS: Info - Contains all field creation info * * RETURN: Status * @@ -445,7 +474,7 @@ acpi_ex_prep_field_value ( switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: - obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); + obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); /* An additional reference for the container */ @@ -461,8 +490,10 @@ acpi_ex_prep_field_value ( case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; - obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node); - obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node); + obj_desc->bank_field.region_obj = acpi_ns_get_attached_object ( + info->region_node); + obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object ( + info->register_node); /* An additional reference for the attached objects */ @@ -481,10 +512,13 @@ acpi_ex_prep_field_value ( case ACPI_TYPE_LOCAL_INDEX_FIELD: - obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node); - obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node); + obj_desc->index_field.index_obj = acpi_ns_get_attached_object ( + info->register_node); + obj_desc->index_field.data_obj = acpi_ns_get_attached_object ( + info->data_register_node); obj_desc->index_field.value = (u32) - (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width)); + (info->field_bit_position / ACPI_MUL_8 ( + obj_desc->field.access_byte_width)); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_REPORT_ERROR (("Null Index Object during field prep\n")); diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 7cfd0684c70..723aaef4bb4 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -115,7 +115,6 @@ acpi_ex_system_memory_space_handler ( return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } - #ifndef ACPI_MISALIGNED_TRANSFERS /* * Hardware does not support non-aligned data transfers, we must verify @@ -134,7 +133,8 @@ acpi_ex_system_memory_space_handler ( */ if ((address < mem_info->mapped_physical_address) || (((acpi_integer) address + length) > - ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { + ((acpi_integer) + mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. @@ -150,7 +150,9 @@ acpi_ex_system_memory_space_handler ( * Don't attempt to map memory beyond the end of the region, and * constrain the maximum mapping size to something reasonable. */ - window_size = (acpi_size) ((mem_info->address + mem_info->length) - address); + window_size = (acpi_size) + ((mem_info->address + mem_info->length) - address); + if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; } @@ -160,8 +162,9 @@ acpi_ex_system_memory_space_handler ( status = acpi_os_map_memory (address, window_size, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", - ACPI_FORMAT_UINT64 (address), (u32) window_size)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not map memory at %8.8X%8.8X, size %X\n", + ACPI_FORMAT_UINT64 (address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS (status); } @@ -177,10 +180,12 @@ acpi_ex_system_memory_space_handler ( * access */ logical_addr_ptr = mem_info->mapped_logical_address + - ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); + ((acpi_integer) address - + (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + "system_memory %d (%d width) Address=%8.8X%8.8X\n", + function, bit_width, ACPI_FORMAT_UINT64 (address))); /* @@ -298,13 +303,15 @@ acpi_ex_system_io_space_handler ( switch (function) { case ACPI_READ: - status = acpi_os_read_port ((acpi_io_address) address, &value32, bit_width); + status = acpi_os_read_port ((acpi_io_address) address, + &value32, bit_width); *value = value32; break; case ACPI_WRITE: - status = acpi_os_write_port ((acpi_io_address) address, (u32) *value, bit_width); + status = acpi_os_write_port ((acpi_io_address) address, + (u32) *value, bit_width); break; default: @@ -375,12 +382,14 @@ acpi_ex_pci_config_space_handler ( case ACPI_READ: *value = 0; - status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width); + status = acpi_os_read_pci_configuration (pci_id, pci_register, + value, bit_width); break; case ACPI_WRITE: - status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width); + status = acpi_os_write_pci_configuration (pci_id, pci_register, + *value, bit_width); break; default: @@ -505,8 +514,7 @@ acpi_ex_data_table_space_handler ( logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address); - - /* Perform the memory read or write */ + /* Perform the memory read or write */ switch (function) { case ACPI_READ: diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 7936329a0e3..21d5c74fa30 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -210,15 +210,15 @@ acpi_ex_resolve_node_to_value ( case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read Node=%p source_desc=%p Type=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "field_read Node=%p source_desc=%p Type=%X\n", node, source_desc, entry_type)); status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc); break; - /* - * For these objects, just return the object attached to the Node - */ + /* For these objects, just return the object attached to the Node */ + case ACPI_TYPE_MUTEX: case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: @@ -233,12 +233,12 @@ acpi_ex_resolve_node_to_value ( acpi_ut_add_reference (obj_desc); break; - /* TYPE_ANY is untyped, and thus there is no object associated with it */ case ACPI_TYPE_ANY: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Untyped entry %p, no attached object!\n", node)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ @@ -259,7 +259,8 @@ acpi_ex_resolve_node_to_value ( default: /* No named references are allowed here */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unsupported Reference opcode %X (%s)\n", source_desc->reference.opcode, acpi_ps_get_opcode_name (source_desc->reference.opcode))); @@ -268,11 +269,12 @@ acpi_ex_resolve_node_to_value ( break; - /* Default case is for unknown types */ - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n", + /* Default case is for unknown types */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Node %p - Unknown object type %X\n", node, entry_type)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); @@ -280,7 +282,7 @@ acpi_ex_resolve_node_to_value ( } /* switch (entry_type) */ - /* Put the object descriptor on the stack */ + /* Return the object descriptor */ *object_ptr = (void *) obj_desc; return_ACPI_STATUS (status); diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 7be60491115..3de45672379 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -54,6 +54,13 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exresolv") +/* Local prototypes */ + +static acpi_status +acpi_ex_resolve_object_to_value ( + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state); + /******************************************************************************* * @@ -96,6 +103,11 @@ acpi_ex_resolve_to_value ( if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } + + if (!*stack_ptr) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } } /* @@ -120,18 +132,17 @@ acpi_ex_resolve_to_value ( * * FUNCTION: acpi_ex_resolve_object_to_value * - * PARAMETERS: stack_ptr - Pointer to a stack location that contains a - * ptr to an internal object. + * PARAMETERS: stack_ptr - Pointer to an internal object * walk_state - Current method state * * RETURN: Status * - * DESCRIPTION: Retrieve the value from an internal object. The Reference type + * DESCRIPTION: Retrieve the value from an internal object. The Reference type * uses the associated AML opcode to determine the value. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_resolve_object_to_value ( union acpi_operand_object **stack_ptr, struct acpi_walk_state *walk_state) @@ -159,7 +170,7 @@ acpi_ex_resolve_object_to_value ( case AML_NAME_OP: /* - * Convert indirect name ptr to a direct name ptr. + * Convert name reference to a namespace node * Then, acpi_ex_resolve_node_to_value can be used to get the value */ temp_node = stack_desc->reference.object; @@ -168,7 +179,7 @@ acpi_ex_resolve_object_to_value ( acpi_ut_remove_reference (stack_desc); - /* Put direct name pointer onto stack and exit */ + /* Return the namespace node */ (*stack_ptr) = temp_node; break; @@ -255,10 +266,19 @@ acpi_ex_resolve_object_to_value ( break; + case AML_INT_NAMEPATH_OP: /* Reference to a named object */ + + /* Get the object pointed to by the namespace node */ + + *stack_ptr = (stack_desc->reference.node)->object; + acpi_ut_add_reference (*stack_ptr); + acpi_ut_remove_reference (stack_desc); + break; default: - ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n", + ACPI_REPORT_ERROR (( + "During resolve, Unknown Reference opcode %X (%s) in %p\n", opcode, acpi_ps_get_opcode_name (opcode), stack_desc)); status = AE_AML_INTERNAL; break; @@ -278,9 +298,8 @@ acpi_ex_resolve_object_to_value ( break; - /* - * These cases may never happen here, but just in case.. - */ + /* These cases may never happen here, but just in case.. */ + case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: @@ -333,9 +352,8 @@ acpi_ex_resolve_multiple ( ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple"); - /* - * Operand can be either a namespace node or an operand descriptor - */ + /* Operand can be either a namespace node or an operand descriptor */ + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { case ACPI_DESC_TYPE_OPERAND: type = obj_desc->common.type; @@ -357,10 +375,8 @@ acpi_ex_resolve_multiple ( return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + /* If type is anything other than a reference, we are done */ - /* - * If type is anything other than a reference, we are done - */ if (type != ACPI_TYPE_LOCAL_REFERENCE) { goto exit; } @@ -382,8 +398,9 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", - node, acpi_ut_get_descriptor_name (node))); + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -440,8 +457,9 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", - node, acpi_ut_get_descriptor_name (node))); + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -468,7 +486,7 @@ acpi_ex_resolve_multiple ( if (return_desc) { status = acpi_ds_method_data_get_value (obj_desc->reference.opcode, - obj_desc->reference.offset, walk_state, &obj_desc); + obj_desc->reference.offset, walk_state, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -500,7 +518,8 @@ acpi_ex_resolve_multiple ( default: - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", obj_desc->reference.opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); } diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index c92890220c3..d8b470eefe7 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -52,6 +52,14 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exresop") +/* Local prototypes */ + +static acpi_status +acpi_ex_check_object_type ( + acpi_object_type type_needed, + acpi_object_type this_type, + void *object); + /******************************************************************************* * @@ -67,7 +75,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_check_object_type ( acpi_object_type type_needed, acpi_object_type this_type, @@ -142,6 +150,7 @@ acpi_ex_resolve_operands ( const struct acpi_opcode_info *op_info; u32 this_arg_type; acpi_object_type type_needed; + u16 target_op = 0; ACPI_FUNCTION_TRACE_U32 ("ex_resolve_operands", opcode); @@ -160,7 +169,8 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Opcode %X [%s] required_operand_types=%8.8X \n", opcode, op_info->name, arg_types)); /* @@ -187,7 +197,7 @@ acpi_ex_resolve_operands ( switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { case ACPI_DESC_TYPE_NAMED: - /* Node */ + /* Namespace Node */ object_type = ((struct acpi_namespace_node *) obj_desc)->type; break; @@ -202,16 +212,16 @@ acpi_ex_resolve_operands ( /* Check for bad acpi_object_type */ if (!acpi_ut_valid_object_type (object_type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Bad operand object type [%X]\n", object_type)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { - /* - * Decode the Reference - */ + /* Decode the Reference */ + op_info = acpi_ps_get_opcode_info (opcode); if (op_info->class == AML_CLASS_UNKNOWN) { return_ACPI_STATUS (AE_AML_BAD_OPCODE); @@ -219,12 +229,17 @@ acpi_ex_resolve_operands ( switch (obj_desc->reference.opcode) { case AML_DEBUG_OP: + target_op = AML_DEBUG_OP; + + /*lint -fallthrough */ + case AML_NAME_OP: case AML_INDEX_OP: case AML_REF_OF_OP: case AML_ARG_OP: case AML_LOCAL_OP: - case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ + case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ + case AML_INT_NAMEPATH_OP: /* Reference to a named object */ ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Operand is a Reference, ref_opcode [%s]\n", @@ -254,10 +269,8 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + /* Get one argument type, point to the next */ - /* - * Get one argument type, point to the next - */ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); INCREMENT_ARG_LIST (arg_types); @@ -271,26 +284,31 @@ acpi_ex_resolve_operands ( if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) && (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) { /* - * String found - the string references a named object and must be - * resolved to a node + * String found - the string references a named object and + * must be resolved to a node */ goto next_operand; } - /* Else not a string - fall through to the normal Reference case below */ + /* + * Else not a string - fall through to the normal Reference + * case below + */ /*lint -fallthrough */ case ARGI_REFERENCE: /* References: */ case ARGI_INTEGER_REF: case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: - case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ - case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ - case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ - - /* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE */ + case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ + case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ - if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ { + /* + * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE + * A Namespace Node is OK as-is + */ + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { goto next_operand; } @@ -300,11 +318,9 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (status); } - if (AML_NAME_OP == obj_desc->reference.opcode) { - /* - * Convert an indirect name ptr to direct name ptr and put - * it on the stack - */ + if (obj_desc->reference.opcode == AML_NAME_OP) { + /* Convert a named reference to the actual named object */ + temp_node = obj_desc->reference.object; acpi_ut_remove_reference (obj_desc); (*stack_ptr) = temp_node; @@ -332,7 +348,6 @@ acpi_ex_resolve_operands ( break; } - /* * Resolve this object to a value */ @@ -392,7 +407,7 @@ acpi_ex_resolve_operands ( /* * The more complex cases allow multiple resolved object types */ - case ARGI_INTEGER: /* Number */ + case ARGI_INTEGER: /* * Need an operand of type ACPI_TYPE_INTEGER, @@ -563,7 +578,7 @@ acpi_ex_resolve_operands ( case ARGI_REGION_OR_FIELD: - /* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */ + /* Need an operand of type REGION or a FIELD in a region */ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_REGION: @@ -614,6 +629,12 @@ acpi_ex_resolve_operands ( break; } + if (target_op == AML_DEBUG_OP) { + /* Allow store of any object to the Debug object */ + + break; + } + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n", acpi_ut_get_object_type_name (obj_desc), obj_desc)); @@ -652,8 +673,7 @@ next_operand: if (GET_CURRENT_ARG_TYPE (arg_types)) { stack_ptr--; } - - } /* while (*Types) */ + } return_ACPI_STATUS (status); } diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index e0fc6aba125..2725db0901b 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -48,11 +48,171 @@ #include #include #include +#include #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exstore") +/* Local prototypes */ + +static void +acpi_ex_do_debug_object ( + union acpi_operand_object *source_desc, + u32 level, + u32 index); + +static acpi_status +acpi_ex_store_object_to_index ( + union acpi_operand_object *val_desc, + union acpi_operand_object *dest_desc, + struct acpi_walk_state *walk_state); + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_debug_object + * + * PARAMETERS: source_desc - Value to be stored + * Level - Indentation level (used for packages) + * Index - Current package element, zero if not pkg + * + * RETURN: None + * + * DESCRIPTION: Handles stores to the Debug Object. + * + ******************************************************************************/ + +static void +acpi_ex_do_debug_object ( + union acpi_operand_object *source_desc, + u32 level, + u32 index) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ex_do_debug_object", source_desc); + + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s", + level, " ")); + + /* Display index for package output only */ + + if (index > 0) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, + "(%.2u) ", index -1)); + } + + if (!source_desc) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "\n")); + return_VOID; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_OPERAND) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: ", + acpi_ut_get_object_type_name (source_desc))); + + if (!acpi_ut_valid_internal_object (source_desc)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, + "%p, Invalid Internal Object!\n", source_desc)); + return_VOID; + } + } + else if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: %p\n", + acpi_ut_get_type_name (((struct acpi_namespace_node *) source_desc)->type), + source_desc)); + return_VOID; + } + else { + return_VOID; + } + + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { + case ACPI_TYPE_INTEGER: + + /* Output correct integer width */ + + if (acpi_gbl_integer_byte_width == 4) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n", + (u32) source_desc->integer.value)); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (source_desc->integer.value))); + } + break; + + case ACPI_TYPE_BUFFER: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]", + (u32) source_desc->buffer.length)); + ACPI_DUMP_BUFFER (source_desc->buffer.pointer, + (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); + break; + + case ACPI_TYPE_STRING: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n", + source_desc->string.length, source_desc->string.pointer)); + break; + + case ACPI_TYPE_PACKAGE: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X Elements]\n", + source_desc->package.count)); + + /* Output the entire contents of the package */ + + for (i = 0; i < source_desc->package.count; i++) { + acpi_ex_do_debug_object (source_desc->package.elements[i], + level+4, i+1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + if (source_desc->reference.opcode == AML_INDEX_OP) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s, 0x%X]\n", + acpi_ps_get_opcode_name (source_desc->reference.opcode), + source_desc->reference.offset)); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s]\n", + acpi_ps_get_opcode_name (source_desc->reference.opcode))); + } + + + if (source_desc->reference.object) { + if (ACPI_GET_DESCRIPTOR_TYPE (source_desc->reference.object) == + ACPI_DESC_TYPE_NAMED) { + acpi_ex_do_debug_object (((struct acpi_namespace_node *) + source_desc->reference.object)->object, + level+4, 0); + } + else { + acpi_ex_do_debug_object (source_desc->reference.object, level+4, 0); + } + } + else if (source_desc->reference.node) { + acpi_ex_do_debug_object ((source_desc->reference.node)->object, + level+4, 0); + } + break; + + default: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p %s\n", + source_desc, acpi_ut_get_object_type_name (source_desc))); + break; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + return_VOID; +} + /******************************************************************************* * @@ -154,8 +314,9 @@ acpi_ex_store ( /* Storing an object into a Name "container" */ - status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, - walk_state, ACPI_IMPLICIT_CONVERSION); + status = acpi_ex_store_object_to_node (source_desc, + ref_desc->reference.object, + walk_state, ACPI_IMPLICIT_CONVERSION); break; @@ -173,7 +334,7 @@ acpi_ex_store ( /* Store to a method local/arg */ status = acpi_ds_store_object_to_local (ref_desc->reference.opcode, - ref_desc->reference.offset, source_desc, walk_state); + ref_desc->reference.offset, source_desc, walk_state); break; @@ -187,60 +348,7 @@ acpi_ex_store ( "**** Write to Debug Object: Object %p %s ****:\n\n", source_desc, acpi_ut_get_object_type_name (source_desc))); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ", - acpi_ut_get_object_type_name (source_desc))); - - if (!acpi_ut_valid_internal_object (source_desc)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, - "%p, Invalid Internal Object!\n", source_desc)); - break; - } - - switch (ACPI_GET_OBJECT_TYPE (source_desc)) { - case ACPI_TYPE_INTEGER: - - if (acpi_gbl_integer_byte_width == 4) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n", - (u32) source_desc->integer.value)); - } - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (source_desc->integer.value))); - } - break; - - - case ACPI_TYPE_BUFFER: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]", - (u32) source_desc->buffer.length)); - ACPI_DUMP_BUFFER (source_desc->buffer.pointer, - (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); - break; - - - case ACPI_TYPE_STRING: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n", - source_desc->string.length, source_desc->string.pointer)); - break; - - - case ACPI_TYPE_PACKAGE: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n", - source_desc->package.count, source_desc->package.elements)); - break; - - - default: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n", - source_desc)); - break; - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + acpi_ex_do_debug_object (source_desc, 0, 0); break; @@ -272,7 +380,7 @@ acpi_ex_store ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_store_object_to_index ( union acpi_operand_object *source_desc, union acpi_operand_object *index_desc, @@ -313,16 +421,22 @@ acpi_ex_store_object_to_index ( if (obj_desc) { /* Decrement reference count by the ref count of the parent package */ - for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + for (i = 0; + i < ((union acpi_operand_object *) + index_desc->reference.object)->common.reference_count; + i++) { acpi_ut_remove_reference (obj_desc); } } *(index_desc->reference.where) = new_desc; - /* Increment reference count by the ref count of the parent package -1 */ + /* Increment ref count by the ref count of the parent package-1 */ - for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + for (i = 1; + i < ((union acpi_operand_object *) + index_desc->reference.object)->common.reference_count; + i++) { acpi_ut_add_reference (new_desc); } @@ -440,9 +554,8 @@ acpi_ex_store_object_to_node ( ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_node", source_desc); - /* - * Get current type of the node, and object attached to Node - */ + /* Get current type of the node, and object attached to Node */ + target_type = acpi_ns_get_type (node); target_desc = acpi_ns_get_attached_object (node); @@ -467,19 +580,18 @@ acpi_ex_store_object_to_node ( target_type = ACPI_TYPE_ANY; } - /* - * Do the actual store operation - */ + /* Do the actual store operation */ + switch (target_type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: - /* - * For fields, copy the source data to the target field. - */ - status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj); + /* For fields, copy the source data to the target field. */ + + status = acpi_ex_write_data_to_field (source_desc, target_desc, + &walk_state->result_obj); break; @@ -493,7 +605,8 @@ acpi_ex_store_object_to_node ( * * Copy and/or convert the source object to a new target object */ - status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state); + status = acpi_ex_store_object_to_object (source_desc, target_desc, + &new_desc, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -526,7 +639,8 @@ acpi_ex_store_object_to_node ( /* No conversions for all other types. Just attach the source object */ - status = acpi_ns_attach_object (node, source_desc, ACPI_GET_OBJECT_TYPE (source_desc)); + status = acpi_ns_attach_object (node, source_desc, + ACPI_GET_OBJECT_TYPE (source_desc)); break; } diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index d3677feb07f..120f30ed0bd 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -81,9 +81,8 @@ acpi_ex_resolve_object ( ACPI_FUNCTION_TRACE ("ex_resolve_object"); - /* - * Ensure we have a Target that can be stored to - */ + /* Ensure we have a Target that can be stored to */ + switch (target_type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -118,16 +117,14 @@ acpi_ex_resolve_object ( break; } - /* - * Must have a Integer, Buffer, or String - */ + /* Must have a Integer, Buffer, or String */ + if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) && (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) && (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) && !((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) { - /* - * Conversion successful but still not a valid type - */ + /* Conversion successful but still not a valid type */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Cannot assign type %s to %s (must be type Int/Str/Buf)\n", acpi_ut_get_object_type_name (source_desc), @@ -140,9 +137,8 @@ acpi_ex_resolve_object ( case ACPI_TYPE_LOCAL_ALIAS: case ACPI_TYPE_LOCAL_METHOD_ALIAS: - /* - * Aliases are resolved by acpi_ex_prep_operands - */ + /* Aliases are resolved by acpi_ex_prep_operands */ + ACPI_REPORT_ERROR (("Store into Alias - should never happen\n")); status = AE_AML_INTERNAL; break; diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 05e1ecae8d9..12d1527669c 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -128,7 +128,8 @@ acpi_ex_store_buffer_to_buffer ( else { /* Truncate the source, copy only what will fit */ - ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length); + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, + target_desc->buffer.length); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Truncating source buffer from %X to %X\n", @@ -183,7 +184,8 @@ acpi_ex_store_string_to_string ( * String will fit in existing non-static buffer. * Clear old string and copy in the new one */ - ACPI_MEMSET (target_desc->string.pointer, 0, (acpi_size) target_desc->string.length + 1); + ACPI_MEMSET (target_desc->string.pointer, 0, + (acpi_size) target_desc->string.length + 1); ACPI_MEMCPY (target_desc->string.pointer, buffer, length); } else { @@ -198,7 +200,8 @@ acpi_ex_store_string_to_string ( ACPI_MEM_FREE (target_desc->string.pointer); } - target_desc->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1); + target_desc->string.pointer = ACPI_MEM_CALLOCATE ( + (acpi_size) length + 1); if (!target_desc->string.pointer) { return_ACPI_STATUS (AE_NO_MEMORY); } diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index f92efc51289..cafa702108d 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -55,8 +55,8 @@ * * FUNCTION: acpi_ex_system_wait_semaphore * - * PARAMETERS: Semaphore - OSD semaphore to wait on - * Timeout - Max time to wait + * PARAMETERS: Semaphore - Semaphore to wait on + * Timeout - Max time to wait * * RETURN: Status * @@ -90,7 +90,8 @@ acpi_ex_system_wait_semaphore ( status = acpi_os_wait_semaphore (semaphore, 1, timeout); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*** Thread awake after blocking, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "*** Thread awake after blocking, %s\n", acpi_format_exception (status))); /* Reacquire the interpreter */ @@ -111,8 +112,8 @@ acpi_ex_system_wait_semaphore ( * * FUNCTION: acpi_ex_system_do_stall * - * PARAMETERS: how_long - The amount of time to stall, - * in microseconds + * PARAMETERS: how_long - The amount of time to stall, + * in microseconds * * RETURN: Status * @@ -141,7 +142,8 @@ acpi_ex_system_do_stall ( * (ACPI specifies 100 usec as max, but this gives some slack in * order to support existing BIOSs) */ - ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long)); + ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", + how_long)); status = AE_AML_OPERAND_VALUE; } else { @@ -156,8 +158,8 @@ acpi_ex_system_do_stall ( * * FUNCTION: acpi_ex_system_do_suspend * - * PARAMETERS: how_long - The amount of time to suspend, - * in milliseconds + * PARAMETERS: how_long - The amount of time to suspend, + * in milliseconds * * RETURN: None * @@ -192,8 +194,8 @@ acpi_ex_system_do_suspend ( * * FUNCTION: acpi_ex_system_acquire_mutex * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -218,16 +220,15 @@ acpi_ex_system_acquire_mutex ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Support for the _GL_ Mutex object -- go get the global lock - */ + /* Support for the _GL_ Mutex object -- go get the global lock */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value); return_ACPI_STATUS (status); } status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore, - (u16) time_desc->integer.value); + (u16) time_desc->integer.value); return_ACPI_STATUS (status); } @@ -236,7 +237,7 @@ acpi_ex_system_acquire_mutex ( * * FUNCTION: acpi_ex_system_release_mutex * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * @@ -261,9 +262,8 @@ acpi_ex_system_release_mutex ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Support for the _GL_ Mutex object -- release the global lock - */ + /* Support for the _GL_ Mutex object -- release the global lock */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { status = acpi_ev_release_global_lock (); return_ACPI_STATUS (status); @@ -278,9 +278,9 @@ acpi_ex_system_release_mutex ( * * FUNCTION: acpi_ex_system_signal_event * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * - * RETURN: AE_OK + * RETURN: Status * * DESCRIPTION: Provides an access point to perform synchronization operations * within the AML. @@ -309,8 +309,8 @@ acpi_ex_system_signal_event ( * * FUNCTION: acpi_ex_system_wait_event * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -333,7 +333,7 @@ acpi_ex_system_wait_event ( if (obj_desc) { status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore, - (u16) time_desc->integer.value); + (u16) time_desc->integer.value); } return_ACPI_STATUS (status); @@ -344,7 +344,7 @@ acpi_ex_system_wait_event ( * * FUNCTION: acpi_ex_system_reset_event * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 40c6abb8b49..5c7ec0c0417 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -67,22 +67,31 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exutils") +/* Local prototypes */ -#ifndef ACPI_NO_METHOD_EXECUTION +static u32 +acpi_ex_digits_needed ( + acpi_integer value, + u32 base); + +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * * FUNCTION: acpi_ex_enter_interpreter * * PARAMETERS: None * + * RETURN: Status + * * DESCRIPTION: Enter the interpreter execution region. Failure to enter * the interpreter region is a fatal system error * ******************************************************************************/ acpi_status -acpi_ex_enter_interpreter (void) +acpi_ex_enter_interpreter ( + void) { acpi_status status; @@ -104,6 +113,8 @@ acpi_ex_enter_interpreter (void) * * PARAMETERS: None * + * RETURN: None + * * DESCRIPTION: Exit the interpreter execution region * * Cases where the interpreter is unlocked: @@ -119,7 +130,8 @@ acpi_ex_enter_interpreter (void) ******************************************************************************/ void -acpi_ex_exit_interpreter (void) +acpi_ex_exit_interpreter ( + void) { acpi_status status; @@ -212,7 +224,8 @@ acpi_ex_acquire_global_lock ( locked = TRUE; } else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not acquire Global Lock, %s\n", acpi_format_exception (status))); } } @@ -228,7 +241,7 @@ acpi_ex_acquire_global_lock ( * PARAMETERS: locked_by_me - Return value from corresponding call to * acquire_global_lock. * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Release the global lock if it is locked. * @@ -269,11 +282,14 @@ acpi_ex_release_global_lock ( * PARAMETERS: Value - Value to be represented * Base - Base of representation * - * RETURN: the number of digits needed to represent Value in Base + * RETURN: The number of digits. + * + * DESCRIPTION: Calculate the number of digits needed to represent the Value + * in the given Base (Radix) * ******************************************************************************/ -u32 +static u32 acpi_ex_digits_needed ( acpi_integer value, u32 base) @@ -312,6 +328,8 @@ acpi_ex_digits_needed ( * PARAMETERS: numeric_id - EISA ID to be converted * out_string - Where to put the converted string (8 bytes) * + * RETURN: None + * * DESCRIPTION: Convert a numeric EISA ID to string representation * ******************************************************************************/ @@ -349,7 +367,10 @@ acpi_ex_eisa_id_to_string ( * PARAMETERS: Value - Value to be converted * out_string - Where to put the converted string (8 bytes) * - * RETURN: Convert a number to string representation + * RETURN: None, string + * + * DESCRIPTOIN: Convert a number to string representation. Assumes string + * buffer is large enough to hold the string. * ******************************************************************************/ diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index 529e922bdc8..b51001e74ee 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -58,7 +58,8 @@ * * RETURN: Status * - * DESCRIPTION: Initialize and validate various ACPI registers + * DESCRIPTION: Initialize and validate the various ACPI registers defined in + * the FADT. * ******************************************************************************/ @@ -75,7 +76,7 @@ acpi_hw_initialize ( /* We must have the ACPI tables by the time we get here */ if (!acpi_gbl_FADT) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No FADT is present\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } @@ -131,7 +132,8 @@ acpi_hw_set_mode ( * transitions are not supported. */ if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { - ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n")); + ACPI_REPORT_ERROR (( + "No ACPI mode transition supported in this system (enable/disable both zero)\n")); return_ACPI_STATUS (AE_OK); } @@ -162,7 +164,8 @@ acpi_hw_set_mode ( } if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Could not write mode change, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -173,7 +176,8 @@ acpi_hw_set_mode ( retry = 3000; while (retry) { if (acpi_hw_get_mode() == mode) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", + mode)); return_ACPI_STATUS (AE_OK); } acpi_os_stall(1000); @@ -185,7 +189,7 @@ acpi_hw_set_mode ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_hw_get_mode * @@ -199,7 +203,8 @@ acpi_hw_set_mode ( ******************************************************************************/ u32 -acpi_hw_get_mode (void) +acpi_hw_get_mode ( + void) { acpi_status status; u32 value; diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 9ac1d639bf5..8daeabb2fc7 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -48,6 +48,13 @@ #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME ("hwgpe") +/* Local prototypes */ + +static acpi_status +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + /****************************************************************************** * @@ -135,6 +142,7 @@ acpi_hw_clear_gpe ( * DESCRIPTION: Return the status of a single GPE. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_hw_get_gpe_status ( @@ -206,7 +214,7 @@ unlock_and_exit: * * RETURN: Status * - * DESCRIPTION: Disable all GPEs within a GPE block + * DESCRIPTION: Disable all GPEs within a single GPE block * ******************************************************************************/ @@ -244,7 +252,7 @@ acpi_hw_disable_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Clear status bits for all GPEs within a GPE block + * DESCRIPTION: Clear status bits for all GPEs within a single GPE block * ******************************************************************************/ @@ -282,8 +290,8 @@ acpi_hw_clear_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes - * combination wake/run GPEs.) + * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes + * combination wake/run GPEs. * ******************************************************************************/ @@ -327,12 +335,12 @@ acpi_hw_enable_runtime_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes - * combination wake/run GPEs.) + * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes + * combination wake/run GPEs. * ******************************************************************************/ -acpi_status +static acpi_status acpi_hw_enable_wakeup_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) @@ -350,7 +358,8 @@ acpi_hw_enable_wakeup_gpe_block ( /* Enable all "wake" GPEs in this register */ - status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake, + status = acpi_hw_low_level_write (8, + gpe_block->register_info[i].enable_for_wake, &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE (status)) { return (status); @@ -369,7 +378,7 @@ acpi_hw_enable_wakeup_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Disable and clear all GPEs + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks * ******************************************************************************/ @@ -397,7 +406,7 @@ acpi_hw_disable_all_gpes ( * * RETURN: Status * - * DESCRIPTION: Enable all GPEs of the given type + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks * ******************************************************************************/ @@ -424,7 +433,7 @@ acpi_hw_enable_all_runtime_gpes ( * * RETURN: Status * - * DESCRIPTION: Enable all GPEs of the given type + * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks * ******************************************************************************/ diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 91af0c2ddcf..6d9e4eb8483 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -87,8 +87,9 @@ acpi_hw_clear_acpi_status ( } } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, - ACPI_BITMASK_ALL_FIXED_STATUS); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -138,28 +139,30 @@ acpi_get_sleep_type_data ( { acpi_status status = AE_OK; struct acpi_parameter_info info; + char *sleep_state_name; ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); - /* - * Validate parameters - */ + /* Validate parameters */ + if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Evaluate the namespace object containing the values for this state - */ + /* Evaluate the namespace object containing the values for this state */ + info.parameters = NULL; - status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], - &info); + info.return_object = NULL; + sleep_state_name = (char *) acpi_gbl_sleep_state_names[sleep_state]; + + status = acpi_ns_evaluate_by_name (sleep_state_name, &info); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", - acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s while evaluating sleep_state [%s]\n", + acpi_format_exception (status), sleep_state_name)); return_ACPI_STATUS (status); } @@ -167,45 +170,57 @@ acpi_get_sleep_type_data ( /* Must have a return object */ if (!info.return_object) { - ACPI_REPORT_ERROR (("Missing Sleep State object\n")); + ACPI_REPORT_ERROR (("No Sleep State object returned from [%s]\n", + sleep_state_name)); status = AE_NOT_EXIST; } /* It must be of type Package */ else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { - ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); + ACPI_REPORT_ERROR (("Sleep State return object is not a Package\n")); status = AE_AML_OPERAND_TYPE; } - /* The package must have at least two elements */ - + /* + * The package must have at least two elements. NOTE (March 2005): This + * goes against the current ACPI spec which defines this object as a + * package with one encoded DWORD element. However, existing practice + * by BIOS vendors seems to be to have 2 or more elements, at least + * one per sleep type (A/B). + */ else if (info.return_object->package.count < 2) { - ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); + ACPI_REPORT_ERROR (( + "Sleep State return package does not have at least two elements\n")); status = AE_AML_NO_OPERAND; } /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { - ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", + else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) + != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) + != ACPI_TYPE_INTEGER)) { + ACPI_REPORT_ERROR (( + "Sleep State return package elements are not both Integers (%s, %s)\n", acpi_ut_get_object_type_name (info.return_object->package.elements[0]), acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { - /* - * Valid _Sx_ package size, type, and value - */ - *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; - *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; + /* Valid _Sx_ package size, type, and value */ + + *sleep_type_a = (u8) + (info.return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) + (info.return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_sleep_state_names[sleep_state], info.return_object, + "%s While evaluating sleep_state [%s], bad Sleep object %p type %s\n", + acpi_format_exception (status), + sleep_state_name, info.return_object, acpi_ut_get_object_type_name (info.return_object))); } @@ -221,9 +236,9 @@ EXPORT_SYMBOL(acpi_get_sleep_type_data); * * PARAMETERS: register_id - Index of ACPI Register to access * - * RETURN: The bit mask to be used when accessing the register + * RETURN: The bitmask to be used when accessing the register * - * DESCRIPTION: Map register_id into a register bit mask. + * DESCRIPTION: Map register_id into a register bitmask. * ******************************************************************************/ @@ -359,7 +374,7 @@ acpi_set_register ( /* Always do a register read first so we can insert the new bits */ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, - bit_reg_info->parent_register, ®ister_value); + bit_reg_info->parent_register, ®ister_value); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -396,7 +411,7 @@ acpi_set_register ( bit_reg_info->access_bit_mask, value); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_ENABLE, (u16) register_value); + ACPI_REGISTER_PM1_ENABLE, (u16) register_value); break; @@ -413,7 +428,7 @@ acpi_set_register ( bit_reg_info->access_bit_mask, value); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, (u16) register_value); + ACPI_REGISTER_PM1_CONTROL, (u16) register_value); break; @@ -427,17 +442,19 @@ acpi_set_register ( ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 ( + acpi_gbl_FADT->xpm2_cnt_blk.address))); ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, bit_reg_info->access_bit_mask, value); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 ( + acpi_gbl_FADT->xpm2_cnt_blk.address))); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); + ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); break; @@ -454,7 +471,9 @@ unlock_and_exit: /* Normalize the value that was read */ - ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); + ACPI_DEBUG_EXEC (register_value = + ((register_value & bit_reg_info->access_bit_mask) >> + bit_reg_info->bit_position)); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n", value, register_value, bit_reg_info->parent_register)); @@ -469,7 +488,7 @@ EXPORT_SYMBOL(acpi_set_register); * * PARAMETERS: use_lock - Mutex hw access * register_id - register_iD + Offset - * return_value - Value that was read from the register + * return_value - Where the register value is returned * * RETURN: Status and the value read. * @@ -557,7 +576,8 @@ acpi_hw_register_read ( break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", + register_id)); status = AE_BAD_PARAMETER; break; } @@ -763,10 +783,11 @@ acpi_hw_low_level_read ( return (AE_BAD_PARAMETER); } - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, - ACPI_FORMAT_UINT64 (address), - acpi_ut_get_region_name (reg->address_space_id))); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, + ACPI_FORMAT_UINT64 (address), + acpi_ut_get_region_name (reg->address_space_id))); return (status); } @@ -841,10 +862,11 @@ acpi_hw_low_level_write ( return (AE_BAD_PARAMETER); } - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, - ACPI_FORMAT_UINT64 (address), - acpi_ut_get_region_name (reg->address_space_id))); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, + ACPI_FORMAT_UINT64 (address), + acpi_ut_get_region_name (reg->address_space_id))); return (status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 77b3e9a8550..415d342aeab 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -43,27 +43,13 @@ */ #include - #include #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME ("hwsleep") -#define METHOD_NAME__BFS "\\_BFS" -#define METHOD_NAME__GTS "\\_GTS" -#define METHOD_NAME__PTS "\\_PTS" -#define METHOD_NAME__SST "\\_SI._SST" -#define METHOD_NAME__WAK "\\_WAK" - -#define ACPI_SST_INDICATOR_OFF 0 -#define ACPI_SST_WORKING 1 -#define ACPI_SST_WAKING 2 -#define ACPI_SST_SLEEPING 3 -#define ACPI_SST_SLEEP_CONTEXT 4 - - -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_set_firmware_waking_vector * @@ -72,7 +58,7 @@ * * RETURN: Status * - * DESCRIPTION: access function for d_firmware_waking_vector field in FACS + * DESCRIPTION: Access function for the firmware_waking_vector field in FACS * ******************************************************************************/ @@ -99,19 +85,20 @@ acpi_set_firmware_waking_vector ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_get_firmware_waking_vector * - * PARAMETERS: *physical_address - Output buffer where contents of + * PARAMETERS: *physical_address - Where the contents of * the firmware_waking_vector field of - * the FACS will be stored. + * the FACS will be returned. * - * RETURN: Status + * RETURN: Status, vector * - * DESCRIPTION: Access function for firmware_waking_vector field in FACS + * DESCRIPTION: Access function for the firmware_waking_vector field in FACS * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector ( @@ -141,7 +128,7 @@ acpi_get_firmware_waking_vector ( #endif -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_prep * @@ -215,7 +202,7 @@ acpi_enter_sleep_state_prep ( break; default: - arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */ + arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is off */ break; } @@ -223,14 +210,15 @@ acpi_enter_sleep_state_prep ( status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } return_ACPI_STATUS (AE_OK); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state * @@ -299,15 +287,18 @@ acpi_enter_sleep_state ( /* Get current value of PM1A control */ - status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Entering sleep state [S%d]\n", sleep_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%d]\n", sleep_state)); /* Clear SLP_EN and SLP_TYP fields */ - PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask); + PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | + sleep_enable_reg_info->access_bit_mask); PM1Bcontrol = PM1Acontrol; /* Insert SLP_TYP bits */ @@ -322,12 +313,14 @@ acpi_enter_sleep_state ( /* Write #1: fill in SLP_TYP data */ - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -341,22 +334,25 @@ acpi_enter_sleep_state ( ACPI_FLUSH_CPU_CACHE (); - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } if (sleep_state > ACPI_STATE_S3) { /* - * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that - * we are still executing!) + * We wanted to sleep > S3, but it didn't happen (by virtue of the + * fact that we are still executing!) * - * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines. + * Wait ten seconds, then try again. This is to get S4/S5 to work on + * all machines. * * We wait so long to allow chipsets that poll this reg very slowly to * still read the right value. Ideally, this block would go @@ -364,7 +360,8 @@ acpi_enter_sleep_state ( */ acpi_os_stall (10000000); - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, sleep_enable_reg_info->access_bit_mask); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -374,7 +371,8 @@ acpi_enter_sleep_state ( /* Wait until we enter sleep state */ do { - status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, + ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -388,7 +386,7 @@ acpi_enter_sleep_state ( EXPORT_SYMBOL(acpi_enter_sleep_state); -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_s4bios * @@ -439,11 +437,13 @@ acpi_enter_sleep_state_s4bios ( ACPI_FLUSH_CPU_CACHE (); - status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8); + status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, + (u32) acpi_gbl_FADT->S4bios_req, 8); do { acpi_os_stall(1000); - status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, + ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -454,7 +454,7 @@ acpi_enter_sleep_state_s4bios ( EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios); -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_leave_sleep_state * @@ -534,18 +534,21 @@ acpi_leave_sleep_state ( arg.integer.value = ACPI_SST_WAKING; status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } arg.integer.value = sleep_state; status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", + acpi_format_exception (status))); } status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", + acpi_format_exception (status))); } /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ @@ -567,15 +570,19 @@ acpi_leave_sleep_state ( /* Enable power button */ - (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + (void) acpi_set_register( + acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, ACPI_MTX_DO_NOT_LOCK); - (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + + (void) acpi_set_register( + acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); arg.integer.value = ACPI_SST_WORKING; status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } return_ACPI_STATUS (status); diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index 1906167d729..49d7b395322 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -43,7 +43,6 @@ */ #include - #include #define _COMPONENT ACPI_HARDWARE @@ -90,7 +89,7 @@ acpi_get_timer_resolution ( * * PARAMETERS: Ticks - Where the timer value is returned * - * RETURN: Status and current ticks + * RETURN: Status and current timer value (ticks) * * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). * @@ -199,5 +198,6 @@ acpi_get_timer_duration ( *time_elapsed = (u32) quotient; return_ACPI_STATUS (status); } + EXPORT_SYMBOL(acpi_get_timer_duration); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 1c0c12336c5..ece7a9dedd5 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -67,7 +67,8 @@ ******************************************************************************/ acpi_status -acpi_ns_root_initialize (void) +acpi_ns_root_initialize ( + void) { acpi_status status; const struct acpi_predefined_names *init_val = NULL; @@ -265,7 +266,7 @@ unlock_and_exit: * * FUNCTION: acpi_ns_lookup * - * PARAMETERS: prefix_node - Search scope if name is not fully qualified + * PARAMETERS: scope_info - Current scope info block * Pathname - Search pathname, in internal format * (as represented in the AML stream) * Type - Type associated with name diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index bfd922c5c7d..5653a19d717 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -49,14 +49,20 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsalloc") +/* Local prototypes */ + +static void +acpi_ns_remove_reference ( + struct acpi_namespace_node *node); + /******************************************************************************* * * FUNCTION: acpi_ns_create_node * - * PARAMETERS: acpi_name - Name of the new node + * PARAMETERS: Name - Name of the new node (4 char ACPI name) * - * RETURN: None + * RETURN: New namespace node (Null on failure) * * DESCRIPTION: Create a namespace node * @@ -145,7 +151,6 @@ acpi_ns_delete_node ( } } - ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); /* @@ -157,57 +162,6 @@ acpi_ns_delete_node ( } -#ifdef ACPI_ALPHABETIC_NAMESPACE -/******************************************************************************* - * - * FUNCTION: acpi_ns_compare_names - * - * PARAMETERS: Name1 - First name to compare - * Name2 - Second name to compare - * - * RETURN: value from strncmp - * - * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an - * underscore are forced to be alphabetically first. - * - ******************************************************************************/ - -int -acpi_ns_compare_names ( - char *name1, - char *name2) -{ - char reversed_name1[ACPI_NAME_SIZE]; - char reversed_name2[ACPI_NAME_SIZE]; - u32 i; - u32 j; - - - /* - * Replace all instances of "underscore" with a value that is smaller so - * that all names that are prefixed with underscore(s) are alphabetically - * first. - * - * Reverse the name bytewise so we can just do a 32-bit compare instead - * of a strncmp. - */ - for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) { - reversed_name1[j] = name1[i]; - if (name1[i] == '_') { - reversed_name1[j] = '*'; - } - - reversed_name2[j] = name2[i]; - if (name2[i] == '_') { - reversed_name2[j] = '*'; - } - } - - return (*(int *) reversed_name1 - *(int *) reversed_name2); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ns_install_node @@ -271,7 +225,8 @@ acpi_ns_install_node ( * alphabetic placement. */ previous_child_node = NULL; - while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) { + while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), + acpi_ut_get_node_name (node)) < 0) { if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { /* Last peer; Clear end-of-list flag */ @@ -429,7 +384,8 @@ acpi_ns_delete_children ( /* There should be only one reference remaining on this node */ if (child_node->reference_count != 1) { - ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n", + ACPI_REPORT_WARNING (( + "Existing references (%d) on node being deleted (%p)\n", child_node->reference_count, child_node)); } @@ -548,7 +504,7 @@ acpi_ns_delete_namespace_subtree ( * ******************************************************************************/ -void +static void acpi_ns_remove_reference ( struct acpi_namespace_node *node) { @@ -683,3 +639,54 @@ acpi_ns_delete_namespace_by_owner ( } +#ifdef ACPI_ALPHABETIC_NAMESPACE +/******************************************************************************* + * + * FUNCTION: acpi_ns_compare_names + * + * PARAMETERS: Name1 - First name to compare + * Name2 - Second name to compare + * + * RETURN: value from strncmp + * + * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an + * underscore are forced to be alphabetically first. + * + ******************************************************************************/ + +int +acpi_ns_compare_names ( + char *name1, + char *name2) +{ + char reversed_name1[ACPI_NAME_SIZE]; + char reversed_name2[ACPI_NAME_SIZE]; + u32 i; + u32 j; + + + /* + * Replace all instances of "underscore" with a value that is smaller so + * that all names that are prefixed with underscore(s) are alphabetically + * first. + * + * Reverse the name bytewise so we can just do a 32-bit compare instead + * of a strncmp. + */ + for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) { + reversed_name1[j] = name1[i]; + if (name1[i] == '_') { + reversed_name1[j] = '*'; + } + + reversed_name2[j] = name2[i]; + if (name2[i] == '_') { + reversed_name2[j] = '*'; + } + } + + return (*(int *) reversed_name1 - *(int *) reversed_name2); +} +#endif + + diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 1f6af3eb6c9..4550e6f9809 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -50,16 +50,32 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsdump") +/* Local prototypes */ -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +acpi_ns_dump_root_devices ( + void); +static acpi_status +acpi_ns_dump_one_device ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); +#endif + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /******************************************************************************* * * FUNCTION: acpi_ns_print_pathname * - * PARAMETERS: num_segment - Number of ACPI name segments + * PARAMETERS: num_segments - Number of ACPI name segments * Pathname - The compressed (internal) path * + * RETURN: None + * * DESCRIPTION: Print an object's full namespace pathname * ******************************************************************************/ @@ -103,6 +119,8 @@ acpi_ns_print_pathname ( * Level - Desired debug level * Component - Caller's component ID * + * RETURN: None + * * DESCRIPTION: Print an object's full namespace pathname * Manages allocation/freeing of a pathname buffer * @@ -137,9 +155,12 @@ acpi_ns_dump_pathname ( * * FUNCTION: acpi_ns_dump_one_object * - * PARAMETERS: Handle - Node to be dumped + * PARAMETERS: obj_handle - Node to be dumped * Level - Nesting level of the handle * Context - Passed into walk_namespace + * return_value - Not used + * + * RETURN: Status * * DESCRIPTION: Dump a single Node * This procedure is a user_function called by acpi_ns_walk_namespace. @@ -394,8 +415,7 @@ acpi_ns_dump_one_object ( return (AE_OK); } - acpi_os_printf ("(R%d)", - obj_desc->common.reference_count); + acpi_os_printf ("(R%d)", obj_desc->common.reference_count); switch (type) { case ACPI_TYPE_METHOD: @@ -551,18 +571,20 @@ cleanup: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_ns_dump_objects * * PARAMETERS: Type - Object type to be dumped + * display_type - 0 or ACPI_DISPLAY_SUMMARY * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX * for an effectively unlimited depth. * owner_id - Dump only objects owned by this ID. Use * ACPI_UINT32_MAX to match all owners. * start_handle - Where in namespace to start/end search * + * RETURN: None + * * DESCRIPTION: Dump typed objects within the loaded namespace. * Uses acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object. * @@ -592,6 +614,39 @@ acpi_ns_dump_objects ( } +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_entry + * + * PARAMETERS: Handle - Node to be dumped + * debug_level - Output level + * + * RETURN: None + * + * DESCRIPTION: Dump a single Node + * + ******************************************************************************/ + +void +acpi_ns_dump_entry ( + acpi_handle handle, + u32 debug_level) +{ + struct acpi_walk_info info; + + + ACPI_FUNCTION_ENTRY (); + + + info.debug_level = debug_level; + info.owner_id = ACPI_UINT32_MAX; + info.display_type = ACPI_DISPLAY_SUMMARY; + + (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); +} + + +#ifdef _ACPI_ASL_COMPILER /******************************************************************************* * * FUNCTION: acpi_ns_dump_tables @@ -601,6 +656,8 @@ acpi_ns_dump_objects ( * max_depth - Maximum depth of dump. Use INT_MAX * for an effectively unlimited depth. * + * RETURN: None + * * DESCRIPTION: Dump the name space, or a portion of it. * ******************************************************************************/ @@ -626,7 +683,7 @@ acpi_ns_dump_tables ( } if (ACPI_NS_ALL == search_base) { - /* entire namespace */ + /* Entire namespace */ search_handle = acpi_gbl_root_node; ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n")); @@ -636,38 +693,6 @@ acpi_ns_dump_tables ( ACPI_UINT32_MAX, search_handle); return_VOID; } - -#endif /* ACPI_FUTURE_USAGE */ - - -/******************************************************************************* - * - * FUNCTION: acpi_ns_dump_entry - * - * PARAMETERS: Handle - Node to be dumped - * debug_level - Output level - * - * DESCRIPTION: Dump a single Node - * - ******************************************************************************/ - -void -acpi_ns_dump_entry ( - acpi_handle handle, - u32 debug_level) -{ - struct acpi_walk_info info; - - - ACPI_FUNCTION_ENTRY (); - - - info.debug_level = debug_level; - info.owner_id = ACPI_UINT32_MAX; - info.display_type = ACPI_DISPLAY_SUMMARY; - - (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); -} - -#endif - +#endif /* _ACPI_ASL_COMPILER */ +#endif /* ACPI_FUTURE_USAGE */ +#endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */ diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index d30a59e6b07..27c4f7cd2a4 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -43,15 +43,18 @@ #include -#include +/* TBD: This entire module is apparently obsolete and should be removed */ + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsdumpdv") - +#ifdef ACPI_OBSOLETE_FUNCTIONS #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#include + /******************************************************************************* * * FUNCTION: acpi_ns_dump_one_device @@ -59,13 +62,16 @@ * PARAMETERS: Handle - Node to be dumped * Level - Nesting level of the handle * Context - Passed into walk_namespace + * return_value - Not used + * + * RETURN: Status * * DESCRIPTION: Dump a single Node that represents a device * This procedure is a user_function called by acpi_ns_walk_namespace. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_dump_one_device ( acpi_handle obj_handle, u32 level, @@ -108,12 +114,15 @@ acpi_ns_dump_one_device ( * * PARAMETERS: None * + * RETURN: None + * * DESCRIPTION: Dump all objects of type "device" * ******************************************************************************/ void -acpi_ns_dump_root_devices (void) +acpi_ns_dump_root_devices ( + void) { acpi_handle sys_bus_handle; acpi_status status; @@ -142,5 +151,6 @@ acpi_ns_dump_root_devices (void) } #endif +#endif diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 0d008d53657..1ae89a1c882 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -52,19 +52,33 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nseval") +/* Local prototypes */ + +static acpi_status +acpi_ns_execute_control_method ( + struct acpi_parameter_info *info); + +static acpi_status +acpi_ns_get_object_value ( + struct acpi_parameter_info *info); + /******************************************************************************* * * FUNCTION: acpi_ns_evaluate_relative * - * PARAMETERS: Pathname - Name of method to execute, If NULL, the - * handle is the object to execute - * Info - Method info block + * PARAMETERS: Pathname - Name of method to execute, If NULL, the + * handle is the object to execute + * Info - Method info block, contains: + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. * * RETURN: Status * - * DESCRIPTION: Find and execute the requested method using the handle as a - * scope + * DESCRIPTION: Evaluate the object or find and execute the requested method * * MUTEX: Locks Namespace * @@ -157,8 +171,8 @@ cleanup1: * * FUNCTION: acpi_ns_evaluate_by_name * - * PARAMETERS: Pathname - Fully qualified pathname to the object - * Info - Contains: + * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Method info block, contains: * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * Params - List of parameters to pass to the method, @@ -167,8 +181,8 @@ cleanup1: * * RETURN: Status * - * DESCRIPTION: Find and execute the requested method passing the given - * parameters + * DESCRIPTION: Evaluate the object or rind and execute the requested method + * passing the given parameters * * MUTEX: Locks Namespace * @@ -241,17 +255,21 @@ cleanup: * * FUNCTION: acpi_ns_evaluate_by_handle * - * PARAMETERS: Handle - Method Node to execute - * Params - List of parameters to pass to the method, - * terminated by NULL. Params itself may be + * PARAMETERS: Info - Method info block, contains: + * Node - Method/Object Node to execute + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be * NULL if no parameters are being passed. - * param_type - Type of Parameter list - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * - * DESCRIPTION: Execute the requested method passing the given parameters + * DESCRIPTION: Evaluate object or execute the requested method passing the + * given parameters * * MUTEX: Locks Namespace * @@ -345,7 +363,16 @@ acpi_ns_evaluate_by_handle ( * * FUNCTION: acpi_ns_execute_control_method * - * PARAMETERS: Info - Method info block (w/params) + * PARAMETERS: Info - Method info block, contains: + * Node - Method Node to execute + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -355,7 +382,7 @@ acpi_ns_evaluate_by_handle ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_execute_control_method ( struct acpi_parameter_info *info) { @@ -414,7 +441,10 @@ acpi_ns_execute_control_method ( * * FUNCTION: acpi_ns_get_object_value * - * PARAMETERS: Info - Method info block (w/params) + * PARAMETERS: Info - Method info block, contains: + * Node - Object's NS node + * return_object - Where to put object value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -424,7 +454,7 @@ acpi_ns_execute_control_method ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_get_object_value ( struct acpi_parameter_info *info) { diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 4a46b380605..362802ae29a 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -50,6 +50,22 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsinit") +/* Local prototypes */ + +static acpi_status +acpi_ns_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + +static acpi_status +acpi_ns_init_one_device ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + /******************************************************************************* * @@ -191,7 +207,7 @@ acpi_ns_initialize_devices ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_init_one_object ( acpi_handle obj_handle, u32 level, @@ -331,7 +347,7 @@ acpi_ns_init_one_object ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_init_one_device ( acpi_handle obj_handle, u32 nesting_level, @@ -374,7 +390,8 @@ acpi_ns_init_one_device ( /* * Run _STA to determine if we can run _INI on the device. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, + pinfo.node, METHOD_NAME__STA)); status = acpi_ut_execute_STA (pinfo.node, &flags); if (ACPI_FAILURE (status)) { @@ -399,8 +416,9 @@ acpi_ns_init_one_device ( /* * The device is present. Run _INI. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); - status = acpi_ns_evaluate_relative ("_INI", &pinfo); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, + pinfo.node, METHOD_NAME__INI)); + status = acpi_ns_evaluate_relative (METHOD_NAME__INI, &pinfo); if (ACPI_FAILURE (status)) { /* No _INI (AE_NOT_FOUND) means device requires no initialization */ diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index 1d7aedf68a7..34e49701660 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -50,9 +50,24 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsload") +/* Local prototypes */ -#ifndef ACPI_NO_METHOD_EXECUTION +static acpi_status +acpi_ns_load_table_by_type ( + acpi_table_type table_type); + +#ifdef ACPI_FUTURE_IMPLEMENTATION +acpi_status +acpi_ns_unload_namespace ( + acpi_handle handle); + +static acpi_status +acpi_ns_delete_subtree ( + acpi_handle start_handle); +#endif + +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * * FUNCTION: acpi_ns_load_table @@ -159,7 +174,7 @@ acpi_ns_load_table ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_load_table_by_type ( acpi_table_type table_type) { @@ -321,8 +336,7 @@ acpi_ns_load_namespace ( } -#ifdef ACPI_FUTURE_USAGE - +#ifdef ACPI_FUTURE_IMPLEMENTATION /******************************************************************************* * * FUNCTION: acpi_ns_delete_subtree @@ -339,7 +353,7 @@ acpi_ns_load_namespace ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_delete_subtree ( acpi_handle start_handle) { @@ -453,8 +467,6 @@ acpi_ns_unload_namespace ( return_ACPI_STATUS (status); } - -#endif /* ACPI_FUTURE_USAGE */ - +#endif #endif diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index b6f8f910eff..d8ce7e39795 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -50,6 +50,14 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsnames") +/* Local prototypes */ + +static void +acpi_ns_build_external_path ( + struct acpi_namespace_node *node, + acpi_size size, + char *name_buffer); + /******************************************************************************* * @@ -66,7 +74,7 @@ * ******************************************************************************/ -void +static void acpi_ns_build_external_path ( struct acpi_namespace_node *node, acpi_size size, @@ -126,7 +134,7 @@ acpi_ns_build_external_path ( * * FUNCTION: acpi_ns_get_external_pathname * - * PARAMETERS: Node - NS node whose pathname is needed + * PARAMETERS: Node - Namespace node whose pathname is needed * * RETURN: Pointer to storage containing the fully qualified name of * the node, In external format (name segments separated by path diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index 4e41e66db61..27258c1ca4f 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -60,6 +60,8 @@ * Type - Type of object, or ACPI_TYPE_ANY if not * known * + * RETURN: Status + * * DESCRIPTION: Record the given object as the value associated with the * name whose acpi_handle is passed. If Object is NULL * and Type is ACPI_TYPE_ANY, set the name as having no value. @@ -97,7 +99,8 @@ acpi_ns_attach_object ( if (!object && (ACPI_TYPE_ANY != type)) { /* Null object */ - ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); + ACPI_REPORT_ERROR (( + "ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -112,7 +115,8 @@ acpi_ns_attach_object ( /* Check if this object is already attached */ if (node->object == object) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj %p already installed in name_obj %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj %p already installed in name_obj %p\n", object, node)); return_ACPI_STATUS (AE_OK); @@ -192,7 +196,7 @@ acpi_ns_attach_object ( * * FUNCTION: acpi_ns_detach_object * - * PARAMETERS: Node - An node whose object will be detached + * PARAMETERS: Node - A Namespace node whose object will be detached * * RETURN: None. * @@ -248,7 +252,7 @@ acpi_ns_detach_object ( * * FUNCTION: acpi_ns_get_attached_object * - * PARAMETERS: Node - Parent Node to be examined + * PARAMETERS: Node - Namespace node * * RETURN: Current value of the object field from the Node whose * handle is passed @@ -284,7 +288,7 @@ acpi_ns_get_attached_object ( * * FUNCTION: acpi_ns_get_secondary_object * - * PARAMETERS: Node - Parent Node to be examined + * PARAMETERS: Node - Namespace node * * RETURN: Current value of the object field from the Node whose * handle is passed. diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 0e6dea23603..af8aaa9cc4f 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -49,15 +49,24 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nssearch") +/* Local prototypes */ + +static acpi_status +acpi_ns_search_parent_tree ( + u32 target_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **return_node); + /******************************************************************************* * * FUNCTION: acpi_ns_search_node * - * PARAMETERS: *target_name - Ascii ACPI name to search for - * *Node - Starting node where search will begin - * Type - Object type to match - * **return_node - Where the matched Named obj is returned + * PARAMETERS: target_name - Ascii ACPI name to search for + * Node - Starting node where search will begin + * Type - Object type to match + * return_node - Where the matched Named obj is returned * * RETURN: Status * @@ -163,10 +172,10 @@ acpi_ns_search_node ( * * FUNCTION: acpi_ns_search_parent_tree * - * PARAMETERS: *target_name - Ascii ACPI name to search for - * *Node - Starting node where search will begin - * Type - Object type to match - * **return_node - Where the matched Node is returned + * PARAMETERS: target_name - Ascii ACPI name to search for + * Node - Starting node where search will begin + * Type - Object type to match + * return_node - Where the matched Node is returned * * RETURN: Status * @@ -257,12 +266,12 @@ acpi_ns_search_parent_tree ( * * PARAMETERS: target_name - Ascii ACPI name to search for (4 chars) * walk_state - Current state of the walk - * *Node - Starting node where search will begin + * Node - Starting node where search will begin * interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x. * Otherwise,search only. * Type - Object type to match * Flags - Flags describing the search restrictions - * **return_node - Where the Node is returned + * return_node - Where the Node is returned * * RETURN: Status * diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 75da76cc0b1..c53b82e94ce 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -51,6 +51,18 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsutils") +/* Local prototypes */ + +static u8 +acpi_ns_valid_path_separator ( + char sep); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +acpi_name +acpi_ns_find_parent_name ( + struct acpi_namespace_node *node_to_search); +#endif + /******************************************************************************* * @@ -59,7 +71,8 @@ * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure + * internal_name - Name or path of the namespace node + * lookup_status - Exception code from NS lookup * * RETURN: None * @@ -121,6 +134,9 @@ acpi_ns_report_error ( * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) * Message - Error message to use on failure + * prefix_node - Prefix relative to the path + * Path - Path to the node + * method_status - Execution status * * RETURN: None * @@ -161,8 +177,8 @@ acpi_ns_report_method_error ( * * FUNCTION: acpi_ns_print_node_pathname * - * PARAMETERS: Node - Object - * Msg - Prefix message + * PARAMETERS: Node - Object + * Message - Prefix message * * DESCRIPTION: Print an object's full namespace pathname * Manages allocation/freeing of a pathname buffer @@ -172,7 +188,7 @@ acpi_ns_report_method_error ( void acpi_ns_print_node_pathname ( struct acpi_namespace_node *node, - char *msg) + char *message) { struct acpi_buffer buffer; acpi_status status; @@ -189,8 +205,8 @@ acpi_ns_print_node_pathname ( status = acpi_ns_handle_to_pathname (node, &buffer); if (ACPI_SUCCESS (status)) { - if (msg) { - acpi_os_printf ("%s ", msg); + if (message) { + acpi_os_printf ("%s ", message); } acpi_os_printf ("[%s] (Node %p)", (char *) buffer.pointer, node); @@ -224,7 +240,7 @@ acpi_ns_valid_root_prefix ( * * FUNCTION: acpi_ns_valid_path_separator * - * PARAMETERS: Sep - Character to be checked + * PARAMETERS: Sep - Character to be checked * * RETURN: TRUE if a valid path separator * @@ -232,7 +248,7 @@ acpi_ns_valid_root_prefix ( * ******************************************************************************/ -u8 +static u8 acpi_ns_valid_path_separator ( char sep) { @@ -245,10 +261,12 @@ acpi_ns_valid_path_separator ( * * FUNCTION: acpi_ns_get_type * - * PARAMETERS: Handle - Parent Node to be examined + * PARAMETERS: Node - Parent Node to be examined * * RETURN: Type field from Node whose handle is passed * + * DESCRIPTION: Return the type of a Namespace node + * ******************************************************************************/ acpi_object_type @@ -271,11 +289,13 @@ acpi_ns_get_type ( * * FUNCTION: acpi_ns_local * - * PARAMETERS: Type - A namespace object type + * PARAMETERS: Type - A namespace object type * * RETURN: LOCAL if names must be found locally in objects of the * passed type, 0 if enclosing scopes should be searched * + * DESCRIPTION: Returns scope rule for the given object type. + * ******************************************************************************/ u32 @@ -303,7 +323,7 @@ acpi_ns_local ( * PARAMETERS: Info - Info struct initialized with the * external name pointer. * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Calculate the length of the internal (AML) namestring * corresponding to the external (ASL) namestring. @@ -551,14 +571,16 @@ acpi_ns_internalize_name ( * * FUNCTION: acpi_ns_externalize_name * - * PARAMETERS: *internal_name - Internal representation of name - * **converted_name - Where to return the resulting - * external representation of name + * PARAMETERS: internal_name_length - Lenth of the internal name below + * internal_name - Internal representation of name + * converted_name_length - Where the length is returned + * converted_name - Where the resulting external name + * is returned * * RETURN: Status * * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) - * to its external form (e.g. "\_PR_.CPU0") + * to its external (printable) form (e.g. "\_PR_.CPU0") * ******************************************************************************/ @@ -717,8 +739,9 @@ acpi_ns_externalize_name ( * * DESCRIPTION: Convert a namespace handle to a real Node * - * Note: Real integer handles allow for more verification - * and keep all pointers within this subsystem. + * Note: Real integer handles would allow for more verification + * and keep all pointers within this subsystem - however this introduces + * more (and perhaps unnecessary) overhead. * ******************************************************************************/ @@ -775,7 +798,7 @@ acpi_ns_convert_entry_to_handle ( return ((acpi_handle) node); -/* --------------------------------------------------- +/* Example future implementation --------------------- if (!Node) { @@ -801,12 +824,13 @@ acpi_ns_convert_entry_to_handle ( * * RETURN: none * - * DESCRIPTION: free memory allocated for table storage. + * DESCRIPTION: free memory allocated for namespace and ACPI table storage. * ******************************************************************************/ void -acpi_ns_terminate (void) +acpi_ns_terminate ( + void) { union acpi_operand_object *obj_desc; @@ -940,7 +964,6 @@ acpi_ns_get_node_by_path ( (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); cleanup: - /* Cleanup */ if (internal_path) { ACPI_MEM_FREE (internal_path); } @@ -948,55 +971,6 @@ cleanup: } -/******************************************************************************* - * - * FUNCTION: acpi_ns_find_parent_name - * - * PARAMETERS: *child_node - Named Obj whose name is to be found - * - * RETURN: The ACPI name - * - * DESCRIPTION: Search for the given obj in its parent scope and return the - * name segment, or "????" if the parent name can't be found - * (which "should not happen"). - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_name -acpi_ns_find_parent_name ( - struct acpi_namespace_node *child_node) -{ - struct acpi_namespace_node *parent_node; - - - ACPI_FUNCTION_TRACE ("ns_find_parent_name"); - - - if (child_node) { - /* Valid entry. Get the parent Node */ - - parent_node = acpi_ns_get_parent_node (child_node); - if (parent_node) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Parent of %p [%4.4s] is %p [%4.4s]\n", - child_node, acpi_ut_get_node_name (child_node), - parent_node, acpi_ut_get_node_name (parent_node))); - - if (parent_node->name.integer) { - return_VALUE ((acpi_name) parent_node->name.integer); - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Unable to find parent of %p (%4.4s)\n", - child_node, acpi_ut_get_node_name (child_node))); - } - - return_VALUE (ACPI_UNKNOWN_NAME); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ns_get_parent_node @@ -1009,7 +983,6 @@ acpi_ns_find_parent_name ( * ******************************************************************************/ - struct acpi_namespace_node * acpi_ns_get_parent_node ( struct acpi_namespace_node *node) @@ -1030,7 +1003,6 @@ acpi_ns_get_parent_node ( node = node->peer; } - return (node->peer); } @@ -1049,7 +1021,6 @@ acpi_ns_get_parent_node ( * ******************************************************************************/ - struct acpi_namespace_node * acpi_ns_get_next_valid_node ( struct acpi_namespace_node *node) @@ -1067,3 +1038,53 @@ acpi_ns_get_next_valid_node ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ns_find_parent_name + * + * PARAMETERS: *child_node - Named Obj whose name is to be found + * + * RETURN: The ACPI name + * + * DESCRIPTION: Search for the given obj in its parent scope and return the + * name segment, or "????" if the parent name can't be found + * (which "should not happen"). + * + ******************************************************************************/ + +acpi_name +acpi_ns_find_parent_name ( + struct acpi_namespace_node *child_node) +{ + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_TRACE ("ns_find_parent_name"); + + + if (child_node) { + /* Valid entry. Get the parent Node */ + + parent_node = acpi_ns_get_parent_node (child_node); + if (parent_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Parent of %p [%4.4s] is %p [%4.4s]\n", + child_node, acpi_ut_get_node_name (child_node), + parent_node, acpi_ut_get_node_name (parent_node))); + + if (parent_node->name.integer) { + return_VALUE ((acpi_name) parent_node->name.integer); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Unable to find parent of %p (%4.4s)\n", + child_node, acpi_ut_get_node_name (child_node))); + } + + return_VALUE (ACPI_UNKNOWN_NAME); +} +#endif + + diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 4de2444df30..f9a7277dca6 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -56,7 +56,7 @@ * * PARAMETERS: Type - Type of node to be searched for * parent_node - Parent node whose children we are - * getting + * getting * child_node - Previous child that was found. * The NEXT child will be returned * diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 1dc995586cb..12ea202257f 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -58,11 +58,11 @@ * FUNCTION: acpi_evaluate_object_typed * * PARAMETERS: Handle - Object handle (optional) - * *Pathname - Object pathname (optional) - * **external_params - List of parameters to pass to method, + * Pathname - Object pathname (optional) + * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. - * *return_buffer - Where to put method's return value (if + * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * return_type - Expected type of return object * @@ -73,6 +73,7 @@ * be valid (non-null) * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_evaluate_object_typed ( @@ -307,7 +308,8 @@ acpi_evaluate_object ( if (ACPI_SUCCESS (status)) { /* Validate/Allocate/Clear caller buffer */ - status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); + status = acpi_ut_initialize_buffer (return_buffer, + buffer_space_needed); if (ACPI_FAILURE (status)) { /* * Caller's buffer is too small or a new one can't be allocated @@ -423,7 +425,8 @@ acpi_walk_namespace ( return_ACPI_STATUS (status); } - status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, + status = acpi_ns_walk_namespace (type, start_object, max_depth, + ACPI_NS_WALK_UNLOCK, user_function, context, return_value); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -525,7 +528,8 @@ acpi_ns_get_device_callback ( } } - status = info->user_function (obj_handle, nesting_level, info->context, return_value); + status = info->user_function (obj_handle, nesting_level, info->context, + return_value); return (status); } diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index f2405efd1b9..8d097914c49 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -57,9 +57,9 @@ * FUNCTION: acpi_get_handle * * PARAMETERS: Parent - Object to search under (search scope). - * path_name - Pointer to an asciiz string containing the - * name - * ret_handle - Where the return handle is placed + * Pathname - Pointer to an asciiz string containing the + * name + * ret_handle - Where the return handle is returned * * RETURN: Status * @@ -220,7 +220,7 @@ EXPORT_SYMBOL(acpi_get_name); * FUNCTION: acpi_get_object_info * * PARAMETERS: Handle - Object Handle - * Info - Where the info is returned + * Buffer - Where the info is returned * * RETURN: Status * diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index 19acf32674b..363e1f6cfb1 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -56,7 +56,7 @@ * FUNCTION: acpi_get_type * * PARAMETERS: Handle - Handle of object whose type is desired - * *ret_type - Where the type will be placed + * ret_type - Where the type will be placed * * RETURN: Status * @@ -258,5 +258,5 @@ unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } -EXPORT_SYMBOL(acpi_get_next_object); +EXPORT_SYMBOL(acpi_get_next_object); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index b5d98895f6a..b7ac68cc9e1 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -50,6 +50,16 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("psargs") +/* Local prototypes */ + +static u32 +acpi_ps_get_next_package_length ( + struct acpi_parse_state *parser_state); + +static union acpi_parse_object * +acpi_ps_get_next_field ( + struct acpi_parse_state *parser_state); + /******************************************************************************* * @@ -64,7 +74,7 @@ * ******************************************************************************/ -u32 +static u32 acpi_ps_get_next_package_length ( struct acpi_parse_state *parser_state) { @@ -78,7 +88,6 @@ acpi_ps_get_next_package_length ( encoded_length = (u32) ACPI_GET8 (parser_state->aml); parser_state->aml++; - switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ { case 0: /* 1-byte encoding (bits 0-5) */ @@ -287,13 +296,14 @@ acpi_ps_get_next_namepath ( * parent tree, but don't open a new scope -- we just want to lookup the * object (MUST BE mode EXECUTE to perform upsearch) */ - status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node); + status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &node); if (ACPI_SUCCESS (status) && method_call) { if (node->type == ACPI_TYPE_METHOD) { - /* - * This name is actually a control method invocation - */ + /* This name is actually a control method invocation */ + method_desc = acpi_ns_get_attached_object (node); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n", @@ -360,7 +370,7 @@ acpi_ps_get_next_namepath ( /* * We got a NOT_FOUND during table load or we encountered * a cond_ref_of(x) where the target does not exist. - * -- either case is ok + * Either case is ok */ status = AE_OK; } @@ -486,12 +496,13 @@ acpi_ps_get_next_simple_arg ( * ******************************************************************************/ -union acpi_parse_object * +static union acpi_parse_object * acpi_ps_get_next_field ( struct acpi_parse_state *parser_state) { - u32 aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + u32 aml_offset = (u32) + ACPI_PTR_DIFF (parser_state->aml, + parser_state->aml_start); union acpi_parse_object *field; u16 opcode; u32 name; @@ -500,7 +511,7 @@ acpi_ps_get_next_field ( ACPI_FUNCTION_TRACE ("ps_get_next_field"); - /* determine field type */ + /* Determine field type */ switch (ACPI_GET8 (parser_state->aml)) { default: @@ -521,7 +532,6 @@ acpi_ps_get_next_field ( break; } - /* Allocate a new field op */ field = acpi_ps_alloc_op (opcode); @@ -582,10 +592,10 @@ acpi_ps_get_next_field ( * * FUNCTION: acpi_ps_get_next_arg * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state + * parser_state - Current parser state object * arg_type - The argument type (AML_*_ARG) - * arg_count - If the argument points to a control method - * the method's argument is returned here. + * return_arg - Where the next arg is returned * * RETURN: Status, and an op object containing the next argument. * @@ -619,7 +629,7 @@ acpi_ps_get_next_arg ( case ARGP_NAME: case ARGP_NAMESTRING: - /* constants, strings, and namestrings are all the same size */ + /* Constants, strings, and namestrings are all the same size */ arg = acpi_ps_alloc_op (AML_BYTE_OP); if (!arg) { @@ -654,7 +664,6 @@ acpi_ps_get_next_arg ( else { arg = field; } - prev = field; } @@ -677,8 +686,8 @@ acpi_ps_get_next_arg ( /* Fill in bytelist data */ - arg->common.value.size = (u32) ACPI_PTR_DIFF (parser_state->pkg_end, - parser_state->aml); + arg->common.value.size = (u32) + ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml); arg->named.data = parser_state->aml; /* Skip to End of byte data */ @@ -706,7 +715,7 @@ acpi_ps_get_next_arg ( status = acpi_ps_get_next_namepath (walk_state, parser_state, arg, 0); } else { - /* single complex argument, nothing returned */ + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; } @@ -716,7 +725,7 @@ acpi_ps_get_next_arg ( case ARGP_DATAOBJ: case ARGP_TERMARG: - /* single complex argument, nothing returned */ + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; break; @@ -727,7 +736,7 @@ acpi_ps_get_next_arg ( case ARGP_OBJLIST: if (parser_state->aml < parser_state->pkg_end) { - /* non-empty list of variable arguments, nothing returned */ + /* Non-empty list of variable arguments, nothing returned */ walk_state->arg_count = ACPI_VAR_ARGS; } diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 03e33fedc11..5744673568c 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -44,6 +44,7 @@ #include #include +#include #include @@ -51,23 +52,6 @@ ACPI_MODULE_NAME ("psopcode") -#define _UNK 0x6B -/* - * Reserved ASCII characters. Do not use any of these for - * internal opcodes, since they are used to differentiate - * name strings from AML opcodes - */ -#define _ASC 0x6C -#define _NAM 0x6C -#define _PFX 0x6D -#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ - -#define MAX_EXTENDED_OPCODE 0x88 -#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) -#define MAX_INTERNAL_OPCODE -#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) - - /******************************************************************************* * * NAME: acpi_gbl_aml_op_info @@ -79,274 +63,9 @@ * ******************************************************************************/ - -/* - * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed - * into a 32-bit number and stored in the master opcode table at the end of this file. - */ - - -#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) -#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) -#define ARGP_ARG0 ARG_NONE -#define ARGP_ARG1 ARG_NONE -#define ARGP_ARG2 ARG_NONE -#define ARGP_ARG3 ARG_NONE -#define ARGP_ARG4 ARG_NONE -#define ARGP_ARG5 ARG_NONE -#define ARGP_ARG6 ARG_NONE -#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BREAK_OP ARG_NONE -#define ARGP_BREAK_POINT_OP ARG_NONE -#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) -#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) -#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) -#define ARGP_CONTINUE_OP ARG_NONE -#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME) -#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_DEBUG_OP ARG_NONE -#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) -#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) -#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) -#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) -#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) -#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) -#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) -#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) -#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LOCAL0 ARG_NONE -#define ARGP_LOCAL1 ARG_NONE -#define ARGP_LOCAL2 ARG_NONE -#define ARGP_LOCAL3 ARG_NONE -#define ARGP_LOCAL4 ARG_NONE -#define ARGP_LOCAL5 ARG_NONE -#define ARGP_LOCAL6 ARG_NONE -#define ARGP_LOCAL7 ARG_NONE -#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) -#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) -#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) -#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_NOOP_OP ARG_NONE -#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_ONE_OP ARG_NONE -#define ARGP_ONES_OP ARG_NONE -#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) -#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) -#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) -#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) -#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_REVISION_OP ARG_NONE -#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) -#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) -#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) -#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) -#define ARGP_TIMER_OP ARG_NONE -#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) -#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) -#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) -#define ARGP_ZERO_OP ARG_NONE - - -/* - * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed - * into a 32-bit number and stored in the master opcode table at the end of this file. - * - * (Used by prep_operands procedure and the ASL Compiler) - */ - - -#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) -#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE -#define ARGI_ARG0 ARG_NONE -#define ARGI_ARG1 ARG_NONE -#define ARGI_ARG2 ARG_NONE -#define ARGI_ARG3 ARG_NONE -#define ARGI_ARG4 ARG_NONE -#define ARGI_ARG5 ARG_NONE -#define ARGI_ARG6 ARG_NONE -#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BREAK_OP ARG_NONE -#define ARGI_BREAK_POINT_OP ARG_NONE -#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_BYTE_OP ARGI_INVALID_OPCODE -#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE -#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) -#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) -#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) -#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE -#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) -#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) -#define ARGI_DEBUG_OP ARG_NONE -#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) -#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) -#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE -#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) -#define ARGI_DWORD_OP ARGI_INVALID_OPCODE -#define ARGI_ELSE_OP ARGI_INVALID_OPCODE -#define ARGI_EVENT_OP ARGI_INVALID_OPCODE -#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_IF_OP ARGI_INVALID_OPCODE -#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) -#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF) -#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) -#define ARGI_LOCAL0 ARG_NONE -#define ARGI_LOCAL1 ARG_NONE -#define ARGI_LOCAL2 ARG_NONE -#define ARGI_LOCAL3 ARG_NONE -#define ARGI_LOCAL4 ARG_NONE -#define ARGI_LOCAL5 ARG_NONE -#define ARGI_LOCAL6 ARG_NONE -#define ARGI_LOCAL7 ARG_NONE -#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) -#define ARGI_METHOD_OP ARGI_INVALID_OPCODE -#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE -#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE -#define ARGI_NAME_OP ARGI_INVALID_OPCODE -#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE -#define ARGI_NOOP_OP ARG_NONE -#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) -#define ARGI_ONE_OP ARG_NONE -#define ARGI_ONES_OP ARG_NONE -#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE -#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE -#define ARGI_QWORD_OP ARGI_INVALID_OPCODE -#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) -#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) -#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) -#define ARGI_RETURN_OP ARGI_INVALID_OPCODE -#define ARGI_REVISION_OP ARG_NONE -#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE -#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) -#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) -#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE -#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF) -#define ARGI_STRING_OP ARGI_INVALID_OPCODE -#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE -#define ARGI_TIMER_OP ARG_NONE -#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) -#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) -#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) -#define ARGI_WHILE_OP ARGI_INVALID_OPCODE -#define ARGI_WORD_OP ARGI_INVALID_OPCODE -#define ARGI_ZERO_OP ARG_NONE - - /* * Summary of opcode types/flags - */ - -/****************************************************************************** + * Opcodes that have associated namespace objects (AML_NSOBJECT flag) @@ -460,14 +179,13 @@ AML_CREATE_DWORD_FIELD_OP AML_CREATE_QWORD_FIELD_OP -******************************************************************************/ + ******************************************************************************/ /* - * Master Opcode information table. A summary of everything we know about each opcode, all in one place. + * Master Opcode information table. A summary of everything we know about each + * opcode, all in one place. */ - - const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /*! [Begin] no source code translation */ @@ -693,8 +411,7 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = * * PARAMETERS: Opcode - The AML opcode * - * RETURN: A pointer to the info about the opcode. NULL if the opcode was - * not found in the table. + * RETURN: A pointer to the info about the opcode. * * DESCRIPTION: Find AML opcode description based on the opcode. * NOTE: This procedure must ALWAYS return a valid pointer! @@ -731,7 +448,8 @@ acpi_ps_get_opcode_info ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode [%4.4X]\n", opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown AML opcode [%4.4X]\n", opcode)); break; } diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index e79edb53cb3..bbfdc1a58c2 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -64,6 +64,23 @@ static u32 acpi_gbl_depth = 0; +/* Local prototypes */ + +static void +acpi_ps_complete_this_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +static acpi_status +acpi_ps_next_parse_state ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + acpi_status callback_status); + +static acpi_status +acpi_ps_parse_loop ( + struct acpi_walk_state *walk_state); + /******************************************************************************* * @@ -100,7 +117,7 @@ acpi_ps_get_opcode_size ( * * PARAMETERS: parser_state - A parser state object * - * RETURN: Status + * RETURN: Next AML opcode * * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) * @@ -117,7 +134,6 @@ acpi_ps_peek_opcode ( aml = parser_state->aml; opcode = (u16) ACPI_GET8 (aml); - if (opcode == AML_EXTOP) { /* Extended opcode */ @@ -142,7 +158,7 @@ acpi_ps_peek_opcode ( * ******************************************************************************/ -void +static void acpi_ps_complete_this_op ( struct acpi_walk_state *walk_state, union acpi_parse_object *op) @@ -272,7 +288,6 @@ acpi_ps_complete_this_op ( next = NULL; } } - prev = next; } } @@ -280,7 +295,7 @@ acpi_ps_complete_this_op ( cleanup: - /* Now we can actually delete the subtree rooted at op */ + /* Now we can actually delete the subtree rooted at Op */ acpi_ps_delete_parse_tree (op); return_VOID; @@ -291,7 +306,9 @@ cleanup: * * FUNCTION: acpi_ps_next_parse_state * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state + * Op - Current parse op + * callback_status - Status from previous operation * * RETURN: Status * @@ -300,7 +317,7 @@ cleanup: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ps_next_parse_state ( struct acpi_walk_state *walk_state, union acpi_parse_object *op, @@ -382,9 +399,8 @@ acpi_ps_next_parse_state ( case AE_CTRL_TRANSFER: - /* - * A method call (invocation) -- transfer control - */ + /* A method call (invocation) -- transfer control */ + status = AE_CTRL_TRANSFER; walk_state->prev_op = op; walk_state->method_call_op = op; @@ -397,6 +413,7 @@ acpi_ps_next_parse_state ( default: + status = callback_status; if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { status = AE_OK; @@ -412,7 +429,7 @@ acpi_ps_next_parse_state ( * * FUNCTION: acpi_ps_parse_loop * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state * * RETURN: Status * @@ -421,7 +438,7 @@ acpi_ps_next_parse_state ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ps_parse_loop ( struct acpi_walk_state *walk_state) { @@ -443,6 +460,7 @@ acpi_ps_parse_loop ( walk_state->arg_types = 0; #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { /* We are restarting a preempted control method */ @@ -471,7 +489,8 @@ acpi_ps_parse_loop ( acpi_format_exception (status))); } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "get_predicate Failed, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "get_predicate Failed, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -492,16 +511,15 @@ acpi_ps_parse_loop ( } #endif - /* - * Iterative parsing loop, while there is more aml to process: - */ + /* Iterative parsing loop, while there is more AML to process: */ + while ((parser_state->aml < parser_state->aml_end) || (op)) { aml_op_start = parser_state->aml; if (!op) { /* Get the next opcode from the AML stream */ walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + parser_state->aml_start); walk_state->opcode = acpi_ps_peek_opcode (parser_state); /* @@ -578,8 +596,10 @@ acpi_ps_parse_loop ( INCREMENT_ARG_LIST (walk_state->arg_types); } - /* Make sure that we found a NAME and didn't run out of arguments */ - + /* + * Make sure that we found a NAME and didn't run out of + * arguments + */ if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) { status = AE_AML_NO_OPERAND; goto close_this_op; @@ -597,12 +617,13 @@ acpi_ps_parse_loop ( status = walk_state->descending_callback (walk_state, &op); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n", - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "During name lookup/catalog, %s\n", + acpi_format_exception (status))); goto close_this_op; } - if (op == NULL) { + if (!op) { continue; } @@ -659,7 +680,7 @@ acpi_ps_parse_loop ( if ((walk_state->descending_callback != NULL)) { /* - * Find the object. This will either insert the object into + * Find the object. This will either insert the object into * the namespace or simply look it up */ walk_state->op = op; @@ -688,11 +709,15 @@ acpi_ps_parse_loop ( } - /* Start arg_count at zero because we don't know if there are any args yet */ - + /* + * Start arg_count at zero because we don't know if there are + * any args yet + */ walk_state->arg_count = 0; - if (walk_state->arg_types) /* Are there any arguments that must be processed? */ { + /* Are there any arguments that must be processed? */ + + if (walk_state->arg_types) { /* Get arguments */ switch (op->common.aml_opcode) { @@ -720,14 +745,18 @@ acpi_ps_parse_loop ( default: - /* Op is not a constant or string, append each argument to the Op */ - + /* + * Op is not a constant or string, append each argument + * to the Op + */ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + walk_state->aml_offset = (u32) + ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); + status = acpi_ps_get_next_arg (walk_state, parser_state, - GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); + GET_CURRENT_ARG_TYPE (walk_state->arg_types), + &arg); if (ACPI_FAILURE (status)) { goto close_this_op; } @@ -752,7 +781,8 @@ acpi_ps_parse_loop ( * Save the length and address of the body */ op->named.data = parser_state->aml; - op->named.length = (u32) (parser_state->pkg_end - parser_state->aml); + op->named.length = (u32) (parser_state->pkg_end - + parser_state->aml); /* Skip body of method */ @@ -773,7 +803,8 @@ acpi_ps_parse_loop ( * to parse them correctly. */ op->named.data = aml_op_start; - op->named.length = (u32) (parser_state->pkg_end - aml_op_start); + op->named.length = (u32) (parser_state->pkg_end - + aml_op_start); /* Skip body */ @@ -785,7 +816,8 @@ acpi_ps_parse_loop ( case AML_WHILE_OP: if (walk_state->control_state) { - walk_state->control_state->control.package_end = parser_state->pkg_end; + walk_state->control_state->control.package_end = + parser_state->pkg_end; } break; @@ -801,8 +833,10 @@ acpi_ps_parse_loop ( /* Check for arguments that need to be processed */ if (walk_state->arg_count) { - /* There are arguments (complex ones), push Op and prepare for argument */ - + /* + * There are arguments (complex ones), push Op and + * prepare for argument + */ status = acpi_ps_push_scope (parser_state, op, walk_state->arg_types, walk_state->arg_count); if (ACPI_FAILURE (status)) { @@ -812,8 +846,10 @@ acpi_ps_parse_loop ( continue; } - /* All arguments have been processed -- Op is complete, prepare for next */ - + /* + * All arguments have been processed -- Op is complete, + * prepare for next + */ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (walk_state->op_info->flags & AML_NAMED) { if (acpi_gbl_depth) { @@ -880,9 +916,8 @@ close_this_op: case AE_CTRL_TRANSFER: - /* - * We are about to transfer to a called method. - */ + /* We are about to transfer to a called method. */ + walk_state->prev_op = op; walk_state->prev_arg_types = walk_state->arg_types; return_ACPI_STATUS (status); @@ -1051,10 +1086,7 @@ close_this_op: * * FUNCTION: acpi_ps_parse_aml * - * PARAMETERS: start_scope - The starting point of the parse. Becomes the - * root of the parsed op tree. - * Aml - Pointer to the raw AML code to parse - * aml_size - Length of the AML to parse + * PARAMETERS: walk_state - Current state * * * RETURN: Status @@ -1076,8 +1108,10 @@ acpi_ps_parse_aml ( ACPI_FUNCTION_TRACE ("ps_parse_aml"); - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Entered with walk_state=%p Aml=%p size=%X\n", - walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Entered with walk_state=%p Aml=%p size=%X\n", + walk_state, walk_state->parser_state.aml, + walk_state->parser_state.aml_size)); /* Create and initialize a new thread state */ @@ -1142,9 +1176,10 @@ acpi_ps_parse_aml ( if ((status == AE_ALREADY_EXISTS) && (!walk_state->method_desc->method.semaphore)) { /* - * This method is marked not_serialized, but it tried to create a named - * object, causing the second thread entrance to fail. We will workaround - * this by marking the method permanently as Serialized. + * This method is marked not_serialized, but it tried to create + * a named object, causing the second thread entrance to fail. + * We will workaround this by marking the method permanently + * as Serialized. */ walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED; walk_state->method_desc->method.concurrency = 1; @@ -1187,7 +1222,8 @@ acpi_ps_parse_aml ( previous_walk_state = walk_state; - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "return_value=%p, implicit_value=%p State=%p\n", walk_state->return_desc, walk_state->implicit_return_obj, walk_state)); /* Check if we have restarted a preempted walk */ @@ -1231,12 +1267,14 @@ acpi_ps_parse_aml ( */ else if (previous_walk_state->caller_return_desc) { if (previous_walk_state->implicit_return_obj) { - *(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj; + *(previous_walk_state->caller_return_desc) = + previous_walk_state->implicit_return_obj; } else { /* NULL if no return value */ - *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc; + *(previous_walk_state->caller_return_desc) = + previous_walk_state->return_desc; } } else { diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index dcbed49608b..8dcd1b1e713 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -65,6 +65,7 @@ union acpi_parse_object * acpi_ps_get_parent_scope ( struct acpi_parse_state *parser_state) { + return (parser_state->scope->parse_scope.op); } @@ -87,8 +88,10 @@ u8 acpi_ps_has_completed_scope ( struct acpi_parse_state *parser_state) { - return ((u8) ((parser_state->aml >= parser_state->scope->parse_scope.arg_end || - !parser_state->scope->parse_scope.arg_count))); + + return ((u8) + ((parser_state->aml >= parser_state->scope->parse_scope.arg_end || + !parser_state->scope->parse_scope.arg_count))); } @@ -167,23 +170,23 @@ acpi_ps_push_scope ( return_ACPI_STATUS (AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; - scope->parse_scope.op = op; - scope->parse_scope.arg_list = remaining_args; - scope->parse_scope.arg_count = arg_count; - scope->parse_scope.pkg_end = parser_state->pkg_end; + scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; + scope->parse_scope.op = op; + scope->parse_scope.arg_list = remaining_args; + scope->parse_scope.arg_count = arg_count; + scope->parse_scope.pkg_end = parser_state->pkg_end; /* Push onto scope stack */ acpi_ut_push_generic_state (&parser_state->scope, scope); if (arg_count == ACPI_VAR_ARGS) { - /* multiple arguments */ + /* Multiple arguments */ scope->parse_scope.arg_end = parser_state->pkg_end; } else { - /* single argument */ + /* Single argument */ scope->parse_scope.arg_end = ACPI_TO_POINTER (ACPI_MAX_PTR); } @@ -221,18 +224,17 @@ acpi_ps_pop_scope ( ACPI_FUNCTION_TRACE ("ps_pop_scope"); - /* - * Only pop the scope if there is in fact a next scope - */ + /* Only pop the scope if there is in fact a next scope */ + if (scope->common.next) { scope = acpi_ut_pop_generic_state (&parser_state->scope); /* return to parsing previous op */ - *op = scope->parse_scope.op; - *arg_list = scope->parse_scope.arg_list; - *arg_count = scope->parse_scope.arg_count; - parser_state->pkg_end = scope->parse_scope.pkg_end; + *op = scope->parse_scope.op; + *arg_list = scope->parse_scope.arg_list; + *arg_count = scope->parse_scope.arg_count; + parser_state->pkg_end = scope->parse_scope.pkg_end; /* All done with this scope state structure */ @@ -241,12 +243,13 @@ acpi_ps_pop_scope ( else { /* empty parse stack, prepare to fetch next opcode */ - *op = NULL; - *arg_list = 0; - *arg_count = 0; + *op = NULL; + *arg_list = 0; + *arg_count = 0; } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count)); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Popped Op %p Args %X\n", *op, *arg_count)); return_VOID; } @@ -257,7 +260,7 @@ acpi_ps_pop_scope ( * * PARAMETERS: parser_state - Current parser state object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Destroy available list, remaining stack levels, and return * root scope diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 2140bd1ac10..d5aafe73fca 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -49,6 +49,14 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("pstree") +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +union acpi_parse_object * +acpi_ps_get_child ( + union acpi_parse_object *op); +#endif + /******************************************************************************* * @@ -57,7 +65,7 @@ * PARAMETERS: Op - Get an argument for this op * Argn - Nth argument to get * - * RETURN: The argument (as an Op object). NULL if argument does not exist + * RETURN: The argument (as an Op object). NULL if argument does not exist * * DESCRIPTION: Get the specified op's argument. * @@ -152,7 +160,6 @@ acpi_ps_append_arg ( return; } - /* Append the argument to the linked argument list */ if (op->common.value.arg) { @@ -164,14 +171,12 @@ acpi_ps_append_arg ( } prev_arg->common.next = arg; } - else { /* No argument list, this will be the first argument */ op->common.value.arg = arg; } - /* Set the parent in this arg and any args linked after it */ while (arg) { @@ -182,73 +187,6 @@ acpi_ps_append_arg ( #ifdef ACPI_FUTURE_USAGE - -/******************************************************************************* - * - * FUNCTION: acpi_ps_get_child - * - * PARAMETERS: Op - Get the child of this Op - * - * RETURN: Child Op, Null if none is found. - * - * DESCRIPTION: Get op's children or NULL if none - * - ******************************************************************************/ -union acpi_parse_object * -acpi_ps_get_child ( - union acpi_parse_object *op) -{ - union acpi_parse_object *child = NULL; - - - ACPI_FUNCTION_ENTRY (); - - - switch (op->common.aml_opcode) { - case AML_SCOPE_OP: - case AML_ELSE_OP: - case AML_DEVICE_OP: - case AML_THERMAL_ZONE_OP: - case AML_INT_METHODCALL_OP: - - child = acpi_ps_get_arg (op, 0); - break; - - - case AML_BUFFER_OP: - case AML_PACKAGE_OP: - case AML_METHOD_OP: - case AML_IF_OP: - case AML_WHILE_OP: - case AML_FIELD_OP: - - child = acpi_ps_get_arg (op, 1); - break; - - - case AML_POWER_RES_OP: - case AML_INDEX_FIELD_OP: - - child = acpi_ps_get_arg (op, 2); - break; - - - case AML_PROCESSOR_OP: - case AML_BANK_FIELD_OP: - - child = acpi_ps_get_arg (op, 3); - break; - - - default: - /* All others have no children */ - break; - } - - return (child); -} - - /******************************************************************************* * * FUNCTION: acpi_ps_get_depth_next @@ -280,21 +218,21 @@ acpi_ps_get_depth_next ( return (NULL); } - /* look for an argument or child */ + /* Look for an argument or child */ next = acpi_ps_get_arg (op, 0); if (next) { return (next); } - /* look for a sibling */ + /* Look for a sibling */ next = op->common.next; if (next) { return (next); } - /* look for a sibling of parent */ + /* Look for a sibling of parent */ parent = op->common.parent; @@ -305,13 +243,13 @@ acpi_ps_get_depth_next ( } if (arg == origin) { - /* reached parent of origin, end search */ + /* Reached parent of origin, end search */ return (NULL); } if (parent->common.next) { - /* found sibling of parent */ + /* Found sibling of parent */ return (parent->common.next); } @@ -323,5 +261,74 @@ acpi_ps_get_depth_next ( return (next); } + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_child + * + * PARAMETERS: Op - Get the child of this Op + * + * RETURN: Child Op, Null if none is found. + * + * DESCRIPTION: Get op's children or NULL if none + * + ******************************************************************************/ + +union acpi_parse_object * +acpi_ps_get_child ( + union acpi_parse_object *op) +{ + union acpi_parse_object *child = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + switch (op->common.aml_opcode) { + case AML_SCOPE_OP: + case AML_ELSE_OP: + case AML_DEVICE_OP: + case AML_THERMAL_ZONE_OP: + case AML_INT_METHODCALL_OP: + + child = acpi_ps_get_arg (op, 0); + break; + + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_METHOD_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + + child = acpi_ps_get_arg (op, 1); + break; + + + case AML_POWER_RES_OP: + case AML_INDEX_FIELD_OP: + + child = acpi_ps_get_arg (op, 2); + break; + + + case AML_PROCESSOR_OP: + case AML_BANK_FIELD_OP: + + child = acpi_ps_get_arg (op, 3); + break; + + + default: + /* All others have no children */ + break; + } + + return (child); +} +#endif + #endif /* ACPI_FUTURE_USAGE */ diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index b3597cb19f8..a10f88715d4 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -45,7 +45,6 @@ #include #include #include -#include #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("psutils") @@ -57,7 +56,7 @@ * * PARAMETERS: None * - * RETURN: scope_op + * RETURN: A new Scope object, null on failure * * DESCRIPTION: Create a Scope and associated namepath op with the root name * @@ -75,7 +74,6 @@ acpi_ps_create_scope_op ( return (NULL); } - scope_op->named.name = ACPI_ROOT_NAME; return (scope_op); } @@ -88,10 +86,9 @@ acpi_ps_create_scope_op ( * PARAMETERS: Op - A newly allocated Op object * Opcode - Opcode to store in the Op * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on - * opcode + * DESCRIPTION: Initialize a parse (Op) object * ******************************************************************************/ @@ -107,7 +104,8 @@ acpi_ps_init_op ( op->common.aml_opcode = opcode; ACPI_DISASM_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name, - (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name))); + (acpi_ps_get_opcode_info (opcode))->name, + sizeof (op->common.aml_op_name))); } @@ -117,7 +115,7 @@ acpi_ps_init_op ( * * PARAMETERS: Opcode - Opcode that will be stored in the new Op * - * RETURN: Pointer to the new Op. + * RETURN: Pointer to the new Op, null on failure * * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on * opcode. A cache of opcodes is available for the pure @@ -275,7 +273,6 @@ acpi_ps_get_name ( union acpi_parse_object *op) { - /* The "generic" object has no name associated with it */ if (op->common.flags & ACPI_PARSEOP_GENERIC) { diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 110d2ce917b..9d20cb2ceb5 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -90,17 +90,15 @@ acpi_ps_delete_parse_tree ( } } - /* - * No more children, this Op is complete. - */ + /* No more children, this Op is complete. */ + next = op->common.next; parent = op->common.parent; acpi_ps_free_op (op); - /* - * If we are back to the starting point, the walk is complete. - */ + /* If we are back to the starting point, the walk is complete. */ + if (op == subtree_root) { return_VOID; } @@ -111,5 +109,6 @@ acpi_ps_delete_parse_tree ( op = parent; } } + return_VOID; } diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index b318ad24726..dba893648e8 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -57,13 +57,16 @@ * * FUNCTION: acpi_psx_execute * - * PARAMETERS: Info->Node - A method object containing both the AML - * address and length. - * **Params - List of parameters to pass to method, + * PARAMETERS: Info - Method info block, contains: + * Node - Method Node to execute + * Parameters - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. - * **return_obj_desc - Return object from execution of the - * method. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -196,9 +199,8 @@ acpi_psx_execute ( goto cleanup3; } - /* - * The walk of the parse tree is where we actually execute the method - */ + /* The walk of the parse tree is where we actually execute the method */ + status = acpi_ps_parse_aml (walk_state); goto cleanup2; /* Walk state already deleted */ @@ -217,7 +219,8 @@ cleanup1: for (i = 0; info->parameters[i]; i++) { /* Ignore errors, just do them all */ - (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT); + (void) acpi_ut_update_object_reference ( + info->parameters[i], REF_DECREMENT); } } diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index 4788c079735..55d264771c4 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -77,21 +77,21 @@ acpi_rs_address16_resource ( u8 **output_buffer, acpi_size *structure_size) { - u8 *buffer = byte_stream_buffer; - struct acpi_resource *output_struct = (void *) *output_buffer; - u8 *temp_ptr; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16); u32 index; u16 temp16; u8 temp8; + u8 *temp_ptr; + u8 *buffer = byte_stream_buffer; + struct acpi_resource *output_struct = (void *) *output_buffer; + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_address16); ACPI_FUNCTION_TRACE ("rs_address16_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -104,9 +104,8 @@ acpi_rs_address16_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS16; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -118,9 +117,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; @@ -140,9 +138,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -165,39 +162,34 @@ acpi_rs_address16_resource ( } } - /* - * Get Granularity (Bytes 6-7) - */ + /* Get Granularity (Bytes 6-7) */ + buffer += 1; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.granularity, buffer); - /* - * Get min_address_range (Bytes 8-9) - */ + /* Get min_address_range (Bytes 8-9) */ + buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.min_address_range, buffer); - /* - * Get max_address_range (Bytes 10-11) - */ + /* Get max_address_range (Bytes 10-11) */ + buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 12-13) - */ + /* Get address_translation_offset (Bytes 12-13) */ + buffer += 2; - ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, buffer); + ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, + buffer); + + /* Get address_length (Bytes 14-15) */ - /* - * Get address_length (Bytes 14-15) - */ buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_length, buffer); - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 2; /* @@ -225,7 +217,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_source.string_ptr = (char *)((u8 * )output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address16.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address16.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -239,9 +232,8 @@ acpi_rs_address16_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.address16.resource_source.string_length = index + 1; @@ -260,14 +252,12 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -305,28 +295,24 @@ acpi_rs_address16_stream ( ACPI_FUNCTION_TRACE ("rs_address16_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x88; buffer += 1; - /* - * Save a pointer to the Length field - to be filled in later - */ + /* Save a pointer to the Length field - to be filled in later */ + length_field = buffer; buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address16.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01); temp8 |= (linked_list->data.address16.decode & 0x01) << 1; @@ -336,9 +322,8 @@ acpi_rs_address16_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address16.resource_type) { @@ -362,39 +347,34 @@ acpi_rs_address16_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.granularity); buffer += 2; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.min_address_range); buffer += 2; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.max_address_range); buffer += 2; - /* - * Set the address translation offset - */ - ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_32_TO_16 (buffer, + &linked_list->data.address16.address_translation_offset); buffer += 2; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_length); buffer += 2; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address16.resource_source.string_length) { temp8 = (u8) linked_list->data.address16.resource_source.index; @@ -403,9 +383,8 @@ acpi_rs_address16_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.address16.resource_source.string_ptr); @@ -413,12 +392,12 @@ acpi_rs_address16_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address16.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + actual_bytes = ACPI_PTR_DIFF (buffer, *output_buffer); *bytes_consumed = actual_bytes; @@ -475,9 +454,8 @@ acpi_rs_address32_resource ( buffer = byte_stream_buffer; struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -490,9 +468,8 @@ acpi_rs_address32_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS32; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -504,35 +481,29 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; - /* - * Producer / Consumer - */ + /* Producer / Consumer */ + output_struct->data.address32.producer_consumer = temp8 & 0x01; - /* - * Decode - */ + /* Decode */ + output_struct->data.address32.decode = (temp8 >> 1) & 0x01; - /* - * Min Address Fixed - */ + /* Min Address Fixed */ + output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01; - /* - * Max Address Fixed - */ + /* Max Address Fixed */ + output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -556,39 +527,34 @@ acpi_rs_address32_resource ( } } - /* - * Get Granularity (Bytes 6-9) - */ + /* Get Granularity (Bytes 6-9) */ + buffer += 1; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.granularity, buffer); - /* - * Get min_address_range (Bytes 10-13) - */ + /* Get min_address_range (Bytes 10-13) */ + buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.min_address_range, buffer); - /* - * Get max_address_range (Bytes 14-17) - */ + /* Get max_address_range (Bytes 14-17) */ + buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 18-21) - */ + /* Get address_translation_offset (Bytes 18-21) */ + buffer += 4; - ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, buffer); + ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, + buffer); + + /* Get address_length (Bytes 22-25) */ - /* - * Get address_length (Bytes 22-25) - */ buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_length, buffer); - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 4; /* @@ -615,7 +581,8 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_source.string_ptr = (char *)((u8 *)output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address32.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address32.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -628,9 +595,8 @@ acpi_rs_address32_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.address32.resource_source.string_length = index + 1; @@ -648,14 +614,12 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -694,29 +658,25 @@ acpi_rs_address32_stream ( buffer = *output_buffer; - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x87; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address32.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01); temp8 |= (linked_list->data.address32.decode & 0x01) << 1; temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2; @@ -725,9 +685,8 @@ acpi_rs_address32_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address32.resource_type) { @@ -751,39 +710,34 @@ acpi_rs_address32_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.granularity); buffer += 4; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.min_address_range); buffer += 4; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.max_address_range); buffer += 4; - /* - * Set the address translation offset - */ - ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_32_TO_32 (buffer, + &linked_list->data.address32.address_translation_offset); buffer += 4; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_length); buffer += 4; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address32.resource_source.string_length) { temp8 = (u8) linked_list->data.address32.resource_source.index; @@ -792,9 +746,8 @@ acpi_rs_address32_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.address32.resource_source.string_ptr); @@ -802,12 +755,12 @@ acpi_rs_address32_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address32.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* @@ -864,9 +817,8 @@ acpi_rs_address64_resource ( struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64); resource_type = *buffer; - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -879,9 +831,8 @@ acpi_rs_address64_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS64; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -893,35 +844,29 @@ acpi_rs_address64_resource ( output_struct->data.address64.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; - /* - * Producer / Consumer - */ + /* Producer / Consumer */ + output_struct->data.address64.producer_consumer = temp8 & 0x01; - /* - * Decode - */ + /* Decode */ + output_struct->data.address64.decode = (temp8 >> 1) & 0x01; - /* - * Min Address Fixed - */ + /* Min Address Fixed */ + output_struct->data.address64.min_address_fixed = (temp8 >> 2) & 0x01; - /* - * Max Address Fixed - */ + /* Max Address Fixed */ + output_struct->data.address64.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -951,33 +896,29 @@ acpi_rs_address64_resource ( buffer += 2; } - /* - * Get Granularity (Bytes 6-13) or (Bytes 8-15) - */ + /* Get Granularity (Bytes 6-13) or (Bytes 8-15) */ + buffer += 1; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.granularity, buffer); - /* - * Get min_address_range (Bytes 14-21) or (Bytes 16-23) - */ + /* Get min_address_range (Bytes 14-21) or (Bytes 16-23) */ + buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.min_address_range, buffer); - /* - * Get max_address_range (Bytes 22-29) or (Bytes 24-31) - */ + /* Get max_address_range (Bytes 22-29) or (Bytes 24-31) */ + buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 30-37) or (Bytes 32-39) - */ + /* Get address_translation_offset (Bytes 30-37) or (Bytes 32-39) */ + buffer += 8; - ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer); + ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, + buffer); + + /* Get address_length (Bytes 38-45) or (Bytes 40-47) */ - /* - * Get address_length (Bytes 38-45) or (Bytes 40-47) - */ buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_length, buffer); @@ -989,14 +930,15 @@ acpi_rs_address64_resource ( /* Get type_specific_attribute (Bytes 48-55) */ buffer += 8; - ACPI_MOVE_64_TO_64 (&output_struct->data.address64.type_specific_attributes, buffer); + ACPI_MOVE_64_TO_64 ( + &output_struct->data.address64.type_specific_attributes, + buffer); } else { output_struct->data.address64.type_specific_attributes = 0; - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 8; /* @@ -1025,7 +967,8 @@ acpi_rs_address64_resource ( output_struct->data.address64.resource_source.string_ptr = (char *)((u8 *)output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address64.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -1042,7 +985,8 @@ acpi_rs_address64_resource ( * Add the terminating null */ *temp_ptr = 0x00; - output_struct->data.address64.resource_source.string_length = index + 1; + output_struct->data.address64.resource_source.string_length = + index + 1; /* * In order for the struct_size to fall on a 32-bit boundary, @@ -1054,14 +998,12 @@ acpi_rs_address64_resource ( } } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -1100,29 +1042,25 @@ acpi_rs_address64_stream ( buffer = *output_buffer; - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x8A; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address64.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address64.producer_consumer & 0x01); temp8 |= (linked_list->data.address64.decode & 0x01) << 1; temp8 |= (linked_list->data.address64.min_address_fixed & 0x01) << 2; @@ -1131,9 +1069,8 @@ acpi_rs_address64_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address64.resource_type) { @@ -1157,39 +1094,34 @@ acpi_rs_address64_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.granularity); buffer += 8; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.min_address_range); buffer += 8; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.max_address_range); buffer += 8; - /* - * Set the address translation offset - */ - ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_64_TO_64 (buffer, + &linked_list->data.address64.address_translation_offset); buffer += 8; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_length); buffer += 8; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address64.resource_source.string_length) { temp8 = (u8) linked_list->data.address64.resource_source.index; @@ -1198,21 +1130,21 @@ acpi_rs_address64_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ - ACPI_STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr); + /* Copy the string */ + + ACPI_STRCPY (temp_pointer, + linked_list->data.address64.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address64.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 8a5f0a52371..98176f2fcb5 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -81,9 +81,8 @@ acpi_rs_get_byte_stream_length ( while (!done) { - /* - * Init the variable that will hold the size to add to the total. - */ + /* Init the variable that will hold the size to add to the total. */ + segment_size = 0; switch (linked_list->id) { @@ -196,7 +195,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 16; if (linked_list->data.address16.resource_source.string_ptr) { - segment_size += linked_list->data.address16.resource_source.string_length; + segment_size += + linked_list->data.address16.resource_source.string_length; segment_size++; } break; @@ -212,7 +212,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 26; if (linked_list->data.address32.resource_source.string_ptr) { - segment_size += linked_list->data.address32.resource_source.string_length; + segment_size += + linked_list->data.address32.resource_source.string_length; segment_size++; } break; @@ -227,7 +228,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 46; if (linked_list->data.address64.resource_source.string_ptr) { - segment_size += linked_list->data.address64.resource_source.string_length; + segment_size += + linked_list->data.address64.resource_source.string_length; segment_size++; } break; @@ -241,38 +243,36 @@ acpi_rs_get_byte_stream_length ( * Index + the length of the null terminated string * Resource Source + 1 for the null. */ - segment_size = 9 + - (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4); + segment_size = 9 + (((acpi_size) + linked_list->data.extended_irq.number_of_interrupts - 1) * 4); if (linked_list->data.extended_irq.resource_source.string_ptr) { - segment_size += linked_list->data.extended_irq.resource_source.string_length; + segment_size += + linked_list->data.extended_irq.resource_source.string_length; segment_size++; } break; default: - /* - * If we get here, everything is out of sync, exit with error - */ + + /* If we get here, everything is out of sync, exit with error */ + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } /* switch (linked_list->Id) */ - /* - * Update the total - */ + /* Update the total */ + byte_stream_size_needed += segment_size; - /* - * Point to the next object - */ + /* Point to the next object */ + linked_list = ACPI_PTR_ADD (struct acpi_resource, linked_list, linked_list->length); } - /* - * This is the data the caller needs - */ + /* This is the data the caller needs */ + *size_needed = byte_stream_size_needed; return_ACPI_STATUS (AE_OK); } @@ -320,9 +320,8 @@ acpi_rs_get_list_length ( while (bytes_parsed < byte_stream_buffer_length) { - /* - * The next byte in the stream is the resource type - */ + /* The next byte in the stream is the resource type */ + resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { @@ -346,9 +345,8 @@ acpi_rs_get_list_length ( ACPI_MOVE_16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp16 = (u16) ACPI_ROUND_UP_to_32_bITS (temp16); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) + @@ -416,9 +414,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 64-bit boundary for the structure - */ + /* Ensure a 64-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_64_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64) + @@ -452,9 +449,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32) + @@ -488,9 +484,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16) + @@ -537,9 +532,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq) + @@ -567,9 +561,8 @@ acpi_rs_get_list_length ( ++buffer; - /* - * Look at the number of bits set - */ + /* Look at the number of bits set */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); for (index = 0; index < 16; index++) { @@ -596,9 +589,8 @@ acpi_rs_get_list_length ( ++buffer; - /* - * Look at the number of bits set - */ + /* Look at the number of bits set */ + temp8 = *buffer; for(index = 0; index < 8; index++) { @@ -670,9 +662,8 @@ acpi_rs_get_list_length ( temp8 = (u8) (temp8 & 0x7); bytes_consumed = temp8 + 1; - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) + (temp8 * sizeof (u8)); @@ -697,21 +688,18 @@ acpi_rs_get_list_length ( return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } - /* - * Update the return value and counter - */ + /* Update the return value and counter */ + buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size); bytes_parsed += bytes_consumed; - /* - * Set the byte stream to point to the next resource - */ + /* Set the byte stream to point to the next resource */ + byte_stream_buffer += bytes_consumed; } - /* - * This is the data the caller needs - */ + /* This is the data the caller needs */ + *size_needed = buffer_size; return_ACPI_STATUS (AE_OK); } @@ -767,9 +755,8 @@ acpi_rs_get_pci_routing_table_length ( top_object_list = package_object->package.elements; for (index = 0; index < number_of_elements; index++) { - /* - * Dereference the sub-package - */ + /* Dereference the sub-package */ + package_element = *top_object_list; /* @@ -778,37 +765,40 @@ acpi_rs_get_pci_routing_table_length ( */ sub_object_list = package_element->package.elements; - /* - * Scan the irq_table_elements for the Source Name String - */ + /* Scan the irq_table_elements for the Source Name String */ + name_found = FALSE; for (table_index = 0; table_index < 4 && !name_found; table_index++) { - if ((ACPI_TYPE_STRING == ACPI_GET_OBJECT_TYPE (*sub_object_list)) || - ((ACPI_TYPE_LOCAL_REFERENCE == ACPI_GET_OBJECT_TYPE (*sub_object_list)) && - ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) { + if ((ACPI_TYPE_STRING == + ACPI_GET_OBJECT_TYPE (*sub_object_list)) || + + ((ACPI_TYPE_LOCAL_REFERENCE == + ACPI_GET_OBJECT_TYPE (*sub_object_list)) && + + ((*sub_object_list)->reference.opcode == + AML_INT_NAMEPATH_OP))) { name_found = TRUE; } else { - /* - * Look at the next element - */ + /* Look at the next element */ + sub_object_list++; } } temp_size_needed += (sizeof (struct acpi_pci_routing_table) - 4); - /* - * Was a String type found? - */ + /* Was a String type found? */ + if (name_found) { if (ACPI_GET_OBJECT_TYPE (*sub_object_list) == ACPI_TYPE_STRING) { /* * The length String.Length field does not include the * terminating NULL, add 1 */ - temp_size_needed += ((acpi_size) (*sub_object_list)->string.length + 1); + temp_size_needed += ((acpi_size) + (*sub_object_list)->string.length + 1); } else { temp_size_needed += acpi_ns_get_pathname_length ( @@ -827,14 +817,14 @@ acpi_rs_get_pci_routing_table_length ( temp_size_needed = ACPI_ROUND_UP_to_64_bITS (temp_size_needed); - /* - * Point to the next union acpi_operand_object - */ + /* Point to the next union acpi_operand_object */ + top_object_list++; } /* - * Adding an extra element to the end of the list, essentially a NULL terminator + * Adding an extra element to the end of the list, essentially a + * NULL terminator */ *buffer_size_needed = temp_size_needed + sizeof (struct acpi_pci_routing_table); return_ACPI_STATUS (AE_OK); diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index a3a0cbfda68..8e0eae0d50b 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -87,9 +87,8 @@ acpi_rs_create_resource_list ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "byte_stream_buffer = %p\n", byte_stream_buffer)); - /* - * Params already validated, so we don't re-validate here - */ + /* Params already validated, so we don't re-validate here */ + byte_stream_buffer_length = byte_stream_buffer->buffer.length; byte_stream_start = byte_stream_buffer->buffer.pointer; @@ -171,9 +170,8 @@ acpi_rs_create_pci_routing_table ( /* Params already validated, so we don't re-validate here */ - /* - * Get the required buffer length - */ + /* Get the required buffer length */ + status = acpi_rs_get_pci_routing_table_length (package_object, &buffer_size_needed); if (ACPI_FAILURE (status)) { @@ -217,9 +215,8 @@ acpi_rs_create_pci_routing_table ( */ user_prt->length = (sizeof (struct acpi_pci_routing_table) - 4); - /* - * Each element of the top-level package must also be a package - */ + /* Each element of the top-level package must also be a package */ + if (ACPI_GET_OBJECT_TYPE (*top_object_list) != ACPI_TYPE_PACKAGE) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(PRT[%X]) Need sub-package, found %s\n", @@ -243,9 +240,8 @@ acpi_rs_create_pci_routing_table ( */ sub_object_list = (*top_object_list)->package.elements; - /* - * 1) First subobject: Dereference the PRT.Address - */ + /* 1) First subobject: Dereference the PRT.Address */ + obj_desc = sub_object_list[0]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->address = obj_desc->integer.value; @@ -257,9 +253,8 @@ acpi_rs_create_pci_routing_table ( return_ACPI_STATUS (AE_BAD_DATA); } - /* - * 2) Second subobject: Dereference the PRT.Pin - */ + /* 2) Second subobject: Dereference the PRT.Pin */ + obj_desc = sub_object_list[1]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->pin = (u32) obj_desc->integer.value; @@ -271,9 +266,8 @@ acpi_rs_create_pci_routing_table ( return_ACPI_STATUS (AE_BAD_DATA); } - /* - * 3) Third subobject: Dereference the PRT.source_name - */ + /* 3) Third subobject: Dereference the PRT.source_name */ + obj_desc = sub_object_list[2]; switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_LOCAL_REFERENCE: @@ -296,7 +290,9 @@ acpi_rs_create_pci_routing_table ( status = acpi_ns_handle_to_pathname ((acpi_handle) node, &path_buffer); - user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; /* include null terminator */ + /* +1 to include null terminator */ + + user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; break; @@ -304,8 +300,10 @@ acpi_rs_create_pci_routing_table ( ACPI_STRCPY (user_prt->source, obj_desc->string.pointer); - /* Add to the Length field the length of the string (add 1 for terminator) */ - + /* + * Add to the Length field the length of the string + * (add 1 for terminator) + */ user_prt->length += obj_desc->string.length + 1; break; @@ -333,9 +331,8 @@ acpi_rs_create_pci_routing_table ( user_prt->length = (u32) ACPI_ROUND_UP_to_64_bITS (user_prt->length); - /* - * 4) Fourth subobject: Dereference the PRT.source_index - */ + /* 4) Fourth subobject: Dereference the PRT.source_index */ + obj_desc = sub_object_list[3]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->source_index = (u32) obj_desc->integer.value; diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index eef1b1f2c68..1935dab2ab5 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -48,9 +48,62 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME ("rsdump") +/* Local prototypes */ -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +static void +acpi_rs_dump_irq ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address16 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address64 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_dma ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_io ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_extended_irq ( + union acpi_resource_data *data); +static void +acpi_rs_dump_fixed_io ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_fixed_memory32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_memory24 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_memory32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_start_depend_fns ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_vendor_specific ( + union acpi_resource_data *data); + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /******************************************************************************* * * FUNCTION: acpi_rs_dump_irq @@ -63,7 +116,7 @@ * ******************************************************************************/ -void +static void acpi_rs_dump_irq ( union acpi_resource_data *data) { @@ -77,13 +130,13 @@ acpi_rs_dump_irq ( acpi_os_printf ("IRQ Resource\n"); acpi_os_printf (" %s Triggered\n", - ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); + ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); + ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); acpi_os_printf (" %s\n", - ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); + ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); acpi_os_printf (" %X Interrupts ( ", irq_data->number_of_interrupts); @@ -108,7 +161,7 @@ acpi_rs_dump_irq ( * ******************************************************************************/ -void +static void acpi_rs_dump_dma ( union acpi_resource_data *data) { @@ -144,7 +197,7 @@ acpi_rs_dump_dma ( } acpi_os_printf (" %sBus Master\n", - ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a "); + ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a "); switch (dma_data->transfer) { @@ -165,7 +218,8 @@ acpi_rs_dump_dma ( break; } - acpi_os_printf (" Number of Channels: %X ( ", dma_data->number_of_channels); + acpi_os_printf (" Number of Channels: %X ( ", + dma_data->number_of_channels); for (index = 0; index < dma_data->number_of_channels; index++) { acpi_os_printf ("%X ", dma_data->channels[index]); @@ -188,7 +242,7 @@ acpi_rs_dump_dma ( * ******************************************************************************/ -void +static void acpi_rs_dump_start_depend_fns ( union acpi_resource_data *data) { @@ -232,8 +286,7 @@ acpi_rs_dump_start_depend_fns ( break; default: - acpi_os_printf (" Invalid performance " - "robustness preference\n"); + acpi_os_printf (" Invalid performance robustness preference\n"); break; } @@ -253,7 +306,7 @@ acpi_rs_dump_start_depend_fns ( * ******************************************************************************/ -void +static void acpi_rs_dump_io ( union acpi_resource_data *data) { @@ -266,19 +319,15 @@ acpi_rs_dump_io ( acpi_os_printf ("Io Resource\n"); acpi_os_printf (" %d bit decode\n", - ACPI_DECODE_16 == io_data->io_decode ? 16 : 10); + ACPI_DECODE_16 == io_data->io_decode ? 16 : 10); - acpi_os_printf (" Range minimum base: %08X\n", - io_data->min_base_address); + acpi_os_printf (" Range minimum base: %08X\n", io_data->min_base_address); - acpi_os_printf (" Range maximum base: %08X\n", - io_data->max_base_address); + acpi_os_printf (" Range maximum base: %08X\n", io_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - io_data->alignment); + acpi_os_printf (" Alignment: %08X\n", io_data->alignment); - acpi_os_printf (" Range Length: %08X\n", - io_data->range_length); + acpi_os_printf (" Range Length: %08X\n", io_data->range_length); return; } @@ -296,7 +345,7 @@ acpi_rs_dump_io ( * ******************************************************************************/ -void +static void acpi_rs_dump_fixed_io ( union acpi_resource_data *data) { @@ -307,11 +356,9 @@ acpi_rs_dump_fixed_io ( acpi_os_printf ("Fixed Io Resource\n"); - acpi_os_printf (" Range base address: %08X", - fixed_io_data->base_address); + acpi_os_printf (" Range base address: %08X", fixed_io_data->base_address); - acpi_os_printf (" Range length: %08X", - fixed_io_data->range_length); + acpi_os_printf (" Range length: %08X", fixed_io_data->range_length); return; } @@ -329,7 +376,7 @@ acpi_rs_dump_fixed_io ( * ******************************************************************************/ -void +static void acpi_rs_dump_vendor_specific ( union acpi_resource_data *data) { @@ -346,7 +393,7 @@ acpi_rs_dump_vendor_specific ( for (index = 0; index < vendor_data->length; index++) { acpi_os_printf (" Byte %X: %08X\n", - index, vendor_data->reserved[index]); + index, vendor_data->reserved[index]); } return; @@ -365,7 +412,7 @@ acpi_rs_dump_vendor_specific ( * ******************************************************************************/ -void +static void acpi_rs_dump_memory24 ( union acpi_resource_data *data) { @@ -378,21 +425,19 @@ acpi_rs_dump_memory24 ( acpi_os_printf ("24-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - memory24_data->read_write_attribute ? - "/Write" : " only"); + ACPI_READ_WRITE_MEMORY == + memory24_data->read_write_attribute ? + "/Write" : " only"); acpi_os_printf (" Range minimum base: %08X\n", - memory24_data->min_base_address); + memory24_data->min_base_address); acpi_os_printf (" Range maximum base: %08X\n", - memory24_data->max_base_address); + memory24_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - memory24_data->alignment); + acpi_os_printf (" Alignment: %08X\n", memory24_data->alignment); - acpi_os_printf (" Range length: %08X\n", - memory24_data->range_length); + acpi_os_printf (" Range length: %08X\n", memory24_data->range_length); return; } @@ -410,7 +455,7 @@ acpi_rs_dump_memory24 ( * ******************************************************************************/ -void +static void acpi_rs_dump_memory32 ( union acpi_resource_data *data) { @@ -423,21 +468,19 @@ acpi_rs_dump_memory32 ( acpi_os_printf ("32-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - memory32_data->read_write_attribute ? - "/Write" : " only"); + ACPI_READ_WRITE_MEMORY == + memory32_data->read_write_attribute ? + "/Write" : " only"); acpi_os_printf (" Range minimum base: %08X\n", - memory32_data->min_base_address); + memory32_data->min_base_address); acpi_os_printf (" Range maximum base: %08X\n", - memory32_data->max_base_address); + memory32_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - memory32_data->alignment); + acpi_os_printf (" Alignment: %08X\n", memory32_data->alignment); - acpi_os_printf (" Range length: %08X\n", - memory32_data->range_length); + acpi_os_printf (" Range length: %08X\n", memory32_data->range_length); return; } @@ -455,11 +498,12 @@ acpi_rs_dump_memory32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_fixed_memory32 ( union acpi_resource_data *data) { - struct acpi_resource_fixed_mem32 *fixed_memory32_data = (struct acpi_resource_fixed_mem32 *) data; + struct acpi_resource_fixed_mem32 *fixed_memory32_data = + (struct acpi_resource_fixed_mem32 *) data; ACPI_FUNCTION_ENTRY (); @@ -468,15 +512,14 @@ acpi_rs_dump_fixed_memory32 ( acpi_os_printf ("32-Bit Fixed Location Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - fixed_memory32_data->read_write_attribute ? - "/Write" : " Only"); + ACPI_READ_WRITE_MEMORY == + fixed_memory32_data->read_write_attribute ? "/Write" : " Only"); acpi_os_printf (" Range base address: %08X\n", - fixed_memory32_data->range_base_address); + fixed_memory32_data->range_base_address); acpi_os_printf (" Range length: %08X\n", - fixed_memory32_data->range_length); + fixed_memory32_data->range_length); return; } @@ -494,7 +537,7 @@ acpi_rs_dump_fixed_memory32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address16 ( union acpi_resource_data *data) { @@ -514,35 +557,30 @@ acpi_rs_dump_address16 ( switch (address16_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address16_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address16_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -551,30 +589,26 @@ acpi_rs_dump_address16 ( switch (address16_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid range attribute\n"); + acpi_os_printf (" Type Specific: Invalid range attribute\n"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address16_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address16_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -589,41 +623,42 @@ acpi_rs_dump_address16 ( } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address16_data->producer_consumer ? + ACPI_CONSUMER == address16_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address16_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address16_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ? - "" : "not"); + ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ? + "" : "not"); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ? - "" : "not"); + ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ? + "" : "not"); acpi_os_printf (" Granularity: %08X\n", - address16_data->granularity); + address16_data->granularity); acpi_os_printf (" Address range min: %08X\n", - address16_data->min_address_range); + address16_data->min_address_range); acpi_os_printf (" Address range max: %08X\n", - address16_data->max_address_range); + address16_data->max_address_range); acpi_os_printf (" Address translation offset: %08X\n", - address16_data->address_translation_offset); + address16_data->address_translation_offset); acpi_os_printf (" Address Length: %08X\n", - address16_data->address_length); + address16_data->address_length); if (0xFF != address16_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address16_data->resource_source.index); + address16_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address16_data->resource_source.string_ptr); + address16_data->resource_source.string_ptr); } return; @@ -642,7 +677,7 @@ acpi_rs_dump_address16 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address32 ( union acpi_resource_data *data) { @@ -661,35 +696,30 @@ acpi_rs_dump_address32 ( switch (address32_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address32_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address32_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -698,30 +728,26 @@ acpi_rs_dump_address32 ( switch (address32_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid Range attribute"); + acpi_os_printf (" Type Specific: Invalid Range attribute"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address32_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address32_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -731,46 +757,48 @@ acpi_rs_dump_address32 ( default: - acpi_os_printf (" Resource Type: 0x%2.2X\n", address32_data->resource_type); + acpi_os_printf (" Resource Type: 0x%2.2X\n", + address32_data->resource_type); break; } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address32_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == address32_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address32_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address32_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ? + "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ? + "" : "not "); acpi_os_printf (" Granularity: %08X\n", - address32_data->granularity); + address32_data->granularity); acpi_os_printf (" Address range min: %08X\n", - address32_data->min_address_range); + address32_data->min_address_range); acpi_os_printf (" Address range max: %08X\n", - address32_data->max_address_range); + address32_data->max_address_range); acpi_os_printf (" Address translation offset: %08X\n", - address32_data->address_translation_offset); + address32_data->address_translation_offset); acpi_os_printf (" Address Length: %08X\n", - address32_data->address_length); + address32_data->address_length); if(0xFF != address32_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address32_data->resource_source.index); + address32_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address32_data->resource_source.string_ptr); + address32_data->resource_source.string_ptr); } return; @@ -789,7 +817,7 @@ acpi_rs_dump_address32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address64 ( union acpi_resource_data *data) { @@ -808,35 +836,30 @@ acpi_rs_dump_address64 ( switch (address64_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address64_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address64_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -845,30 +868,26 @@ acpi_rs_dump_address64 ( switch (address64_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid Range attribute"); + acpi_os_printf (" Type Specific: Invalid Range attribute"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address64_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address64_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -878,49 +897,51 @@ acpi_rs_dump_address64 ( default: - acpi_os_printf (" Resource Type: 0x%2.2X\n", address64_data->resource_type); + acpi_os_printf (" Resource Type: 0x%2.2X\n", + address64_data->resource_type); break; } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address64_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == address64_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address64_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address64_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ? + "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? + "" : "not "); acpi_os_printf (" Granularity: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->granularity)); + ACPI_FORMAT_UINT64 (address64_data->granularity)); acpi_os_printf (" Address range min: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->min_address_range)); + ACPI_FORMAT_UINT64 (address64_data->min_address_range)); acpi_os_printf (" Address range max: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->max_address_range)); + ACPI_FORMAT_UINT64 (address64_data->max_address_range)); acpi_os_printf (" Address translation offset: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->address_translation_offset)); + ACPI_FORMAT_UINT64 (address64_data->address_translation_offset)); acpi_os_printf (" Address Length: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->address_length)); + ACPI_FORMAT_UINT64 (address64_data->address_length)); acpi_os_printf (" Type Specific Attributes: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes)); + ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes)); if (0xFF != address64_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address64_data->resource_source.index); + address64_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address64_data->resource_source.string_ptr); + address64_data->resource_source.string_ptr); } return; @@ -939,7 +960,7 @@ acpi_rs_dump_address64 ( * ******************************************************************************/ -void +static void acpi_rs_dump_extended_irq ( union acpi_resource_data *data) { @@ -953,23 +974,22 @@ acpi_rs_dump_extended_irq ( acpi_os_printf ("Extended IRQ Resource\n"); acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == ext_irq_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == ext_irq_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s\n", - ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ? - "Level" : "Edge"); + ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ? + "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ? - "low" : "high"); + ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ? + "low" : "high"); acpi_os_printf (" %s\n", - ACPI_SHARED == ext_irq_data->shared_exclusive ? - "Shared" : "Exclusive"); + ACPI_SHARED == ext_irq_data->shared_exclusive ? + "Shared" : "Exclusive"); - acpi_os_printf (" Interrupts : %X ( ", - ext_irq_data->number_of_interrupts); + acpi_os_printf (" Interrupts : %X ( ", ext_irq_data->number_of_interrupts); for (index = 0; index < ext_irq_data->number_of_interrupts; index++) { acpi_os_printf ("%X ", ext_irq_data->interrupts[index]); @@ -979,9 +999,10 @@ acpi_rs_dump_extended_irq ( if(0xFF != ext_irq_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X", - ext_irq_data->resource_source.index); + ext_irq_data->resource_source.index); + acpi_os_printf (" Resource Source: %s", - ext_irq_data->resource_source.string_ptr); + ext_irq_data->resource_source.string_ptr); } return; @@ -992,7 +1013,7 @@ acpi_rs_dump_extended_irq ( * * FUNCTION: acpi_rs_dump_resource_list * - * PARAMETERS: Data - pointer to the resource structure to dump. + * PARAMETERS: Resource - pointer to the resource structure to dump. * * RETURN: None * @@ -1096,7 +1117,7 @@ acpi_rs_dump_resource_list ( * * FUNCTION: acpi_rs_dump_irq_list * - * PARAMETERS: Data - pointer to the routing table to dump. + * PARAMETERS: route_table - pointer to the routing table to dump. * * RETURN: None * @@ -1124,20 +1145,17 @@ acpi_rs_dump_irq_list ( acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++); acpi_os_printf (" Address: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (prt_element->address)); + ACPI_FORMAT_UINT64 (prt_element->address)); acpi_os_printf (" Pin: %X\n", prt_element->pin); acpi_os_printf (" Source: %s\n", prt_element->source); - acpi_os_printf (" source_index: %X\n", - prt_element->source_index); + acpi_os_printf (" source_index: %X\n", prt_element->source_index); buffer += prt_element->length; - prt_element = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer); - - if(0 == prt_element->length) { + if (0 == prt_element->length) { done = TRUE; } } diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index 972c746d37e..23a4d149fac 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -81,67 +81,60 @@ acpi_rs_io_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_io); ACPI_FUNCTION_TRACE ("rs_io_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 8; output_struct->id = ACPI_RSTYPE_IO; - /* - * Check Decode - */ + /* Check Decode */ + buffer += 1; temp8 = *buffer; output_struct->data.io.io_decode = temp8 & 0x01; - /* - * Check min_base Address - */ + /* Check min_base Address */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.io.min_base_address = temp16; - /* - * Check max_base Address - */ + /* Check max_base Address */ + buffer += 2; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.io.max_base_address = temp16; - /* - * Check Base alignment - */ + /* Check Base alignment */ + buffer += 2; temp8 = *buffer; output_struct->data.io.alignment = temp8; - /* - * Check range_length - */ + /* Check range_length */ + buffer += 1; temp8 = *buffer; output_struct->data.io.range_length = temp8; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -179,43 +172,39 @@ acpi_rs_fixed_io_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_fixed_io); ACPI_FUNCTION_TRACE ("rs_fixed_io_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 4; output_struct->id = ACPI_RSTYPE_FIXED_IO; - /* - * Check Range Base Address - */ + /* Check Range Base Address */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.fixed_io.base_address = temp16; - /* - * Check range_length - */ + /* Check range_length */ + buffer += 2; temp8 = *buffer; output_struct->data.fixed_io.range_length = temp8; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -251,55 +240,48 @@ acpi_rs_io_stream ( ACPI_FUNCTION_TRACE ("rs_io_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x47; buffer += 1; - /* - * Io Information Byte - */ + /* Io Information Byte */ + temp8 = (u8) (linked_list->data.io.io_decode & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + temp16 = (u16) linked_list->data.io.min_base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + temp16 = (u16) linked_list->data.io.max_base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the base alignment - */ + /* Set the base alignment */ + temp8 = (u8) linked_list->data.io.alignment; *buffer = temp8; buffer += 1; - /* - * Set the range length - */ + /* Set the range length */ + temp8 = (u8) linked_list->data.io.range_length; *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -335,32 +317,28 @@ acpi_rs_fixed_io_stream ( ACPI_FUNCTION_TRACE ("rs_fixed_io_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x4B; buffer += 1; - /* - * Set the Range base address - */ + /* Set the Range base address */ + temp16 = (u16) linked_list->data.fixed_io.base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the range length - */ + /* Set the range length */ + temp8 = (u8) linked_list->data.fixed_io.range_length; *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -399,21 +377,20 @@ acpi_rs_dma_resource ( u8 temp8 = 0; u8 index; u8 i; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_dma); ACPI_FUNCTION_TRACE ("rs_dma_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 3; output_struct->id = ACPI_RSTYPE_DMA; - /* - * Point to the 8-bits of Byte 1 - */ + /* Point to the 8-bits of Byte 1 */ + buffer += 1; temp8 = *buffer; @@ -430,46 +407,40 @@ acpi_rs_dma_resource ( output_struct->data.dma.number_of_channels = i; if (i > 0) { - /* - * Calculate the structure size based upon the number of interrupts - */ + /* Calculate the structure size based upon the number of interrupts */ + struct_size += ((acpi_size) i - 1) * 4; } - /* - * Point to Byte 2 - */ + /* Point to Byte 2 */ + buffer += 1; temp8 = *buffer; - /* - * Check for transfer preference (Bits[1:0]) - */ + /* Check for transfer preference (Bits[1:0]) */ + output_struct->data.dma.transfer = temp8 & 0x03; if (0x03 == output_struct->data.dma.transfer) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid DMA.Transfer preference (3)\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid DMA.Transfer preference (3)\n")); return_ACPI_STATUS (AE_BAD_DATA); } - /* - * Get bus master preference (Bit[2]) - */ + /* Get bus master preference (Bit[2]) */ + output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01; - /* - * Get channel speed support (Bits[6:5]) - */ + /* Get channel speed support (Bits[6:5]) */ + output_struct->data.dma.type = (temp8 >> 5) & 0x03; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -506,16 +477,14 @@ acpi_rs_dma_stream ( ACPI_FUNCTION_TRACE ("rs_dma_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x2A; buffer += 1; temp8 = 0; - /* - * Loop through all of the Channels and set the mask bits - */ + /* Loop through all of the Channels and set the mask bits */ + for (index = 0; index < linked_list->data.dma.number_of_channels; index++) { @@ -526,9 +495,8 @@ acpi_rs_dma_stream ( *buffer = temp8; buffer += 1; - /* - * Set the DMA Info - */ + /* Set the DMA Info */ + temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5); temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2); temp8 |= (linked_list->data.dma.transfer & 0x03); @@ -536,9 +504,8 @@ acpi_rs_dma_stream ( *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index fd07a8702fb..8a2b630be45 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -83,7 +83,8 @@ acpi_rs_irq_resource ( u8 temp8 = 0; u8 index; u8 i; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_irq); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_irq); ACPI_FUNCTION_TRACE ("rs_irq_resource"); @@ -91,15 +92,14 @@ acpi_rs_irq_resource ( /* * The number of bytes consumed are contained in the descriptor - * (Bits:0-1) + * (Bits:0-1) */ temp8 = *buffer; *bytes_consumed = (temp8 & 0x03) + 1; output_struct->id = ACPI_RSTYPE_IRQ; - /* - * Point to the 16-bits of Bytes 1 and 2 - */ + /* Point to the 16-bits of Bytes 1 and 2 */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -118,22 +118,19 @@ acpi_rs_irq_resource ( output_struct->data.irq.number_of_interrupts = i; if (i > 0) { - /* - * Calculate the structure size based upon the number of interrupts - */ + /* Calculate the structure size based upon the number of interrupts */ + struct_size += ((acpi_size) i - 1) * 4; } - /* - * Point to Byte 3 if it is used - */ + /* Point to Byte 3 if it is used */ + if (4 == *bytes_consumed) { buffer += 2; temp8 = *buffer; - /* - * Check for HE, LL interrupts - */ + /* Check for HE, LL interrupts */ + switch (temp8 & 0x09) { case 0x01: /* HE */ output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; @@ -152,13 +149,13 @@ acpi_rs_irq_resource ( * so 0x00 and 0x09 are illegal. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid interrupt polarity/trigger in resource list, %X\n", temp8)); + "Invalid interrupt polarity/trigger in resource list, %X\n", + temp8)); return_ACPI_STATUS (AE_BAD_DATA); } - /* - * Check for sharable - */ + /* Check for sharable */ + output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01; } else { @@ -171,14 +168,12 @@ acpi_rs_irq_resource ( output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -234,9 +229,8 @@ acpi_rs_irq_stream ( buffer += 1; temp16 = 0; - /* - * Loop through all of the interrupts and set the mask bits - */ + /* Loop through all of the interrupts and set the mask bits */ + for(index = 0; index < linked_list->data.irq.number_of_interrupts; index++) { @@ -247,9 +241,8 @@ acpi_rs_irq_stream ( ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the IRQ Info byte if needed. - */ + /* Set the IRQ Info byte if needed. */ + if (IRqinfo_byte_needed) { temp8 = 0; temp8 = (u8) ((linked_list->data.irq.shared_exclusive & @@ -267,9 +260,8 @@ acpi_rs_irq_stream ( buffer += 1; } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -309,15 +301,15 @@ acpi_rs_extended_irq_resource ( u8 temp8 = 0; u8 *temp_ptr; u8 index; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_ext_irq); ACPI_FUNCTION_TRACE ("rs_extended_irq_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -330,9 +322,8 @@ acpi_rs_extended_irq_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_EXT_IRQ; - /* - * Point to the Byte3 - */ + /* Point to the Byte3 */ + buffer += 2; temp8 = *buffer; @@ -347,21 +338,18 @@ acpi_rs_extended_irq_resource ( * - Edge/Level are defined opposite in the table vs the headers */ output_struct->data.extended_irq.edge_level = - (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + + /* Check Interrupt Polarity */ - /* - * Check Interrupt Polarity - */ output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1; - /* - * Check for sharable - */ + /* Check for sharable */ + output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01; - /* - * Point to Byte4 (IRQ Table length) - */ + /* Point to Byte4 (IRQ Table length) */ + buffer += 1; temp8 = *buffer; @@ -379,14 +367,12 @@ acpi_rs_extended_irq_resource ( */ struct_size += (temp8 - 1) * 4; - /* - * Point to Byte5 (First IRQ Number) - */ + /* Point to Byte5 (First IRQ Number) */ + buffer += 1; - /* - * Cycle through every IRQ in the table - */ + /* Cycle through every IRQ in the table */ + for (index = 0; index < temp8; index++) { ACPI_MOVE_32_TO_32 ( &output_struct->data.extended_irq.interrupts[index], buffer); @@ -407,7 +393,8 @@ acpi_rs_extended_irq_resource ( * we add 1 to the length. */ if (*bytes_consumed > - ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) { + ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + + (5 + 1)) { /* Dereference the Index */ temp8 = *buffer; @@ -417,13 +404,13 @@ acpi_rs_extended_irq_resource ( buffer += 1; - /* - * Point the String pointer to the end of this structure. - */ + /* Point the String pointer to the end of this structure. */ + output_struct->data.extended_irq.resource_source.string_ptr = (char *)((char *) output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.extended_irq.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -436,9 +423,8 @@ acpi_rs_extended_irq_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.extended_irq.resource_source.string_length = index + 1; @@ -456,14 +442,12 @@ acpi_rs_extended_irq_resource ( output_struct->data.extended_irq.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -501,21 +485,18 @@ acpi_rs_extended_irq_stream ( ACPI_FUNCTION_TRACE ("rs_extended_irq_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x89; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Interrupt vector flags - */ + /* Set the Interrupt vector flags */ + temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01); temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3); @@ -532,17 +513,15 @@ acpi_rs_extended_irq_stream ( temp8 |= 0x2; } - /* - * Set the Interrupt Polarity - */ + /* Set the Interrupt Polarity */ + temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2); *buffer = temp8; buffer += 1; - /* - * Set the Interrupt table length - */ + /* Set the Interrupt table length */ + temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts; *buffer = temp8; @@ -555,18 +534,16 @@ acpi_rs_extended_irq_stream ( buffer += 4; } - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.extended_irq.resource_source.string_length) { *buffer = (u8) linked_list->data.extended_irq.resource_source.index; buffer += 1; temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source.string_ptr); @@ -574,12 +551,12 @@ acpi_rs_extended_irq_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1); + buffer += (acpi_size) (ACPI_STRLEN ( + linked_list->data.extended_irq.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index e49c1e030f9..db7bcb4e60e 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -55,7 +55,7 @@ * * PARAMETERS: resource_start_byte - Byte 0 of a resource descriptor * - * RETURN: The Resource Type (Name) with no extraneous bits + * RETURN: The Resource Type with no extraneous bits * * DESCRIPTION: Extract the Resource Type/Name from the first byte of * a resource descriptor. @@ -70,28 +70,25 @@ acpi_rs_get_resource_type ( ACPI_FUNCTION_ENTRY (); - /* - * Determine if this is a small or large resource - */ + /* Determine if this is a small or large resource */ + switch (resource_start_byte & ACPI_RDESC_TYPE_MASK) { case ACPI_RDESC_TYPE_SMALL: - /* - * Small Resource Type -- Only bits 6:3 are valid - */ + /* Small Resource Type -- Only bits 6:3 are valid */ + return ((u8) (resource_start_byte & ACPI_RDESC_SMALL_MASK)); case ACPI_RDESC_TYPE_LARGE: - /* - * Large Resource Type -- All bits are valid - */ + /* Large Resource Type -- All bits are valid */ + return (resource_start_byte); default: - /* No other types of resource descriptor */ + /* Invalid type */ break; } @@ -135,9 +132,8 @@ acpi_rs_byte_stream_to_list ( while (bytes_parsed < byte_stream_buffer_length && !end_tag_processed) { - /* - * The next byte in the stream is the resource type - */ + /* The next byte in the stream is the resource type */ + resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { @@ -299,28 +295,23 @@ acpi_rs_byte_stream_to_list ( return_ACPI_STATUS (status); } - /* - * Update the return value and counter - */ + /* Update the return value and counter */ + bytes_parsed += bytes_consumed; - /* - * Set the byte stream to point to the next resource - */ + /* Set the byte stream to point to the next resource */ + byte_stream_buffer += bytes_consumed; - /* - * Set the Buffer to the next structure - */ + /* Set the Buffer to the next structure */ + resource = ACPI_CAST_PTR (struct acpi_resource, buffer); resource->length = (u32) ACPI_ALIGN_RESOURCE_SIZE (resource->length); buffer += ACPI_ALIGN_RESOURCE_SIZE (structure_size); + } - } /* end while */ + /* Check the reason for exiting the while loop */ - /* - * Check the reason for exiting the while loop - */ if (!end_tag_processed) { return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); } @@ -424,9 +415,8 @@ acpi_rs_list_to_byte_stream ( */ status = acpi_rs_end_tag_stream (linked_list, &buffer, &bytes_consumed); - /* - * An End Tag indicates the end of the Resource Template - */ + /* An End Tag indicates the end of the Resource Template */ + done = TRUE; break; @@ -488,27 +478,25 @@ acpi_rs_list_to_byte_stream ( default: /* * If we get here, everything is out of sync, - * so exit with an error + * so exit with an error */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type (%X) in resource list\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid descriptor type (%X) in resource list\n", linked_list->id)); status = AE_BAD_DATA; break; - - } /* switch (linked_list->Id) */ + } if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* - * Set the Buffer to point to the open byte - */ + /* Set the Buffer to point to the open byte */ + buffer += bytes_consumed; - /* - * Point to the next object - */ + /* Point to the next object */ + linked_list = ACPI_PTR_ADD (struct acpi_resource, linked_list, linked_list->length); } diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index 7c935aecf07..91d0207f01a 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -81,15 +81,15 @@ acpi_rs_memory24_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_mem24); ACPI_FUNCTION_TRACE ("rs_memory24_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -97,48 +97,41 @@ acpi_rs_memory24_resource ( *bytes_consumed = (acpi_size) temp16 + 3; output_struct->id = ACPI_RSTYPE_MEM24; - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.memory24.read_write_attribute = temp8 & 0x01; - /* - * Get min_base_address (Bytes 4-5) - */ + /* Get min_base_address (Bytes 4-5) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.min_base_address = temp16; - /* - * Get max_base_address (Bytes 6-7) - */ + /* Get max_base_address (Bytes 6-7) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.max_base_address = temp16; - /* - * Get Alignment (Bytes 8-9) - */ + /* Get Alignment (Bytes 8-9) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.alignment = temp16; - /* - * Get range_length (Bytes 10-11) - */ + /* Get range_length (Bytes 10-11) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.memory24.range_length = temp16; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -174,53 +167,45 @@ acpi_rs_memory24_stream ( ACPI_FUNCTION_TRACE ("rs_memory24_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x81; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x09; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.min_base_address); buffer += 2; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.max_base_address); buffer += 2; - /* - * Set the base alignment - */ + /* Set the base alignment */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.alignment); buffer += 2; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.range_length); buffer += 2; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -258,15 +243,15 @@ acpi_rs_memory32_range_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_mem32); ACPI_FUNCTION_TRACE ("rs_memory32_range_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -285,45 +270,38 @@ acpi_rs_memory32_range_resource ( * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8) */ - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.memory32.read_write_attribute = temp8 & 0x01; - /* - * Get min_base_address (Bytes 4-7) - */ + /* Get min_base_address (Bytes 4-7) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.min_base_address, buffer); buffer += 4; - /* - * Get max_base_address (Bytes 8-11) - */ + /* Get max_base_address (Bytes 8-11) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.max_base_address, buffer); buffer += 4; - /* - * Get Alignment (Bytes 12-15) - */ + /* Get Alignment (Bytes 12-15) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.alignment, buffer); buffer += 4; - /* - * Get range_length (Bytes 16-19) - */ + /* Get range_length (Bytes 16-19) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.range_length, buffer); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -361,15 +339,15 @@ acpi_rs_fixed_memory32_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_fixed_mem32); ACPI_FUNCTION_TRACE ("rs_fixed_memory32_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -378,32 +356,28 @@ acpi_rs_fixed_memory32_resource ( output_struct->id = ACPI_RSTYPE_FIXED_MEM32; - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01; - /* - * Get range_base_address (Bytes 4-7) - */ - ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, buffer); + /* Get range_base_address (Bytes 4-7) */ + + ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, + buffer); buffer += 4; - /* - * Get range_length (Bytes 8-11) - */ + /* Get range_length (Bytes 8-11) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_length, buffer); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -439,54 +413,46 @@ acpi_rs_memory32_range_stream ( ACPI_FUNCTION_TRACE ("rs_memory32_range_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x85; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x11; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); buffer += 4; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); buffer += 4; - /* - * Set the base alignment - */ + /* Set the base alignment */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.alignment); buffer += 4; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.range_length); buffer += 4; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -522,44 +488,38 @@ acpi_rs_fixed_memory32_stream ( ACPI_FUNCTION_TRACE ("rs_fixed_memory32_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x86; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x09; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range base address - */ + /* Set the Range base address */ + ACPI_MOVE_32_TO_32 (buffer, - &linked_list->data.fixed_memory32.range_base_address); + &linked_list->data.fixed_memory32.range_base_address); buffer += 4; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_32 (buffer, - &linked_list->data.fixed_memory32.range_length); + &linked_list->data.fixed_memory32.range_length); buffer += 4; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index d16be44b5df..a1f1741f0d8 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -84,24 +84,20 @@ acpi_rs_end_tag_resource ( ACPI_FUNCTION_TRACE ("rs_end_tag_resource"); - /* - * The number of bytes consumed is static - */ + /* The number of bytes consumed is static */ + *bytes_consumed = 2; - /* - * Fill out the structure - */ + /* Fill out the structure */ + output_struct->id = ACPI_RSTYPE_END_TAG; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = 0; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -136,9 +132,8 @@ acpi_rs_end_tag_stream ( ACPI_FUNCTION_TRACE ("rs_end_tag_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x79; buffer += 1; @@ -151,9 +146,8 @@ acpi_rs_end_tag_stream ( *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -192,21 +186,20 @@ acpi_rs_vendor_resource ( u16 temp16 = 0; u8 temp8 = 0; u8 index; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_vendor); ACPI_FUNCTION_TRACE ("rs_vendor_resource"); - /* - * Dereference the Descriptor to find if this is a large or small item. - */ + /* Dereference the Descriptor to find if this is a large or small item. */ + temp8 = *buffer; if (temp8 & 0x80) { - /* - * Large Item, point to the length field - */ + /* Large Item, point to the length field */ + buffer += 1; /* Dereference */ @@ -222,9 +215,8 @@ acpi_rs_vendor_resource ( buffer += 2; } else { - /* - * Small Item, dereference the size - */ + /* Small Item, dereference the size */ + temp16 = (u8)(*buffer & 0x07); /* Calculate bytes consumed */ @@ -251,14 +243,12 @@ acpi_rs_vendor_resource ( */ struct_size += ACPI_ROUND_UP_to_32_bITS (temp16); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -295,13 +285,11 @@ acpi_rs_vendor_stream ( ACPI_FUNCTION_TRACE ("rs_vendor_stream"); - /* - * Dereference the length to find if this is a large or small item. - */ + /* Dereference the length to find if this is a large or small item. */ + if(linked_list->data.vendor_specific.length > 7) { - /* - * Large Item, Set the descriptor field and length bytes - */ + /* Large Item, Set the descriptor field and length bytes */ + *buffer = 0x84; buffer += 1; @@ -311,9 +299,8 @@ acpi_rs_vendor_stream ( buffer += 2; } else { - /* - * Small Item, Set the descriptor field - */ + /* Small Item, Set the descriptor field */ + temp8 = 0x70; temp8 |= (u8) linked_list->data.vendor_specific.length; @@ -321,9 +308,8 @@ acpi_rs_vendor_stream ( buffer += 1; } - /* - * Loop through all of the Vendor Specific fields - */ + /* Loop through all of the Vendor Specific fields */ + for (index = 0; index < linked_list->data.vendor_specific.length; index++) { temp8 = linked_list->data.vendor_specific.reserved[index]; @@ -331,9 +317,8 @@ acpi_rs_vendor_stream ( buffer += 1; } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -370,40 +355,37 @@ acpi_rs_start_depend_fns_resource ( u8 *buffer = byte_stream_buffer; struct acpi_resource *output_struct = (void *) *output_buffer; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_start_dpf); ACPI_FUNCTION_TRACE ("rs_start_depend_fns_resource"); - /* - * The number of bytes consumed are contained in the descriptor (Bits:0-1) - */ + /* The number of bytes consumed are found in the descriptor (Bits:0-1) */ + temp8 = *buffer; *bytes_consumed = (temp8 & 0x01) + 1; output_struct->id = ACPI_RSTYPE_START_DPF; - /* - * Point to Byte 1 if it is used - */ + /* Point to Byte 1 if it is used */ + if (2 == *bytes_consumed) { buffer += 1; temp8 = *buffer; - /* - * Check Compatibility priority - */ + /* Check Compatibility priority */ + output_struct->data.start_dpf.compatibility_priority = temp8 & 0x03; if (3 == output_struct->data.start_dpf.compatibility_priority) { return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE); } - /* - * Check Performance/Robustness preference - */ + /* Check Performance/Robustness preference */ + output_struct->data.start_dpf.performance_robustness = (temp8 >> 2) & 0x03; if (3 == output_struct->data.start_dpf.performance_robustness) { @@ -412,20 +394,18 @@ acpi_rs_start_depend_fns_resource ( } else { output_struct->data.start_dpf.compatibility_priority = - ACPI_ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; output_struct->data.start_dpf.performance_robustness = - ACPI_ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -466,24 +446,20 @@ acpi_rs_end_depend_fns_resource ( ACPI_FUNCTION_TRACE ("rs_end_depend_fns_resource"); - /* - * The number of bytes consumed is static - */ + /* The number of bytes consumed is static */ + *bytes_consumed = 1; - /* - * Fill out the structure - */ + /* Fill out the structure */ + output_struct->id = ACPI_RSTYPE_END_DPF; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -533,9 +509,8 @@ acpi_rs_start_depend_fns_stream ( *buffer = 0x31; buffer += 1; - /* - * Set the Priority Byte Definition - */ + /* Set the Priority Byte Definition */ + temp8 = 0; temp8 = (u8) ((linked_list->data.start_dpf.performance_robustness & 0x03) << 2); @@ -546,9 +521,8 @@ acpi_rs_start_depend_fns_stream ( buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -582,15 +556,13 @@ acpi_rs_end_depend_fns_stream ( ACPI_FUNCTION_TRACE ("rs_end_depend_fns_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x38; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index ee9ce13c053..700cf7d65d7 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -83,10 +83,10 @@ acpi_rs_get_prt_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_PRT", ACPI_BTYPE_PACKAGE, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRT, + ACPI_BTYPE_PACKAGE, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -136,10 +136,10 @@ acpi_rs_get_crs_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_CRS", ACPI_BTYPE_BUFFER, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__CRS, + ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -175,6 +175,7 @@ acpi_rs_get_crs_method_data ( * and the contents of the callers buffer is undefined. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_rs_get_prs_method_data ( @@ -190,10 +191,10 @@ acpi_rs_get_prs_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_PRS", ACPI_BTYPE_BUFFER, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRS, + ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -218,6 +219,7 @@ acpi_rs_get_prs_method_data ( * FUNCTION: acpi_rs_get_method_data * * PARAMETERS: Handle - a handle to the containing object + * Path - Path to method, relative to Handle * ret_buffer - a pointer to a buffer structure for the * results * @@ -246,9 +248,8 @@ acpi_rs_get_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ + /* Execute the method, no parameters */ + status = acpi_ut_evaluate_object (handle, path, ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -314,18 +315,16 @@ acpi_rs_set_srs_method_data ( return_ACPI_STATUS (status); } - /* - * Init the param object - */ + /* Init the param object */ + params[0] = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!params[0]) { acpi_os_free (buffer.pointer); return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Set up the parameter object - */ + /* Set up the parameter object */ + params[0]->buffer.length = (u32) buffer.length; params[0]->buffer.pointer = buffer.pointer; params[0]->common.flags = AOPOBJ_DATA_VALID; @@ -335,10 +334,9 @@ acpi_rs_set_srs_method_data ( info.parameters = params; info.parameter_type = ACPI_PARAM_ARGS; - /* - * Execute the method, no return value - */ - status = acpi_ns_evaluate_relative ("_SRS", &info); + /* Execute the method, no return value */ + + status = acpi_ns_evaluate_relative (METHOD_NAME__SRS, &info); if (ACPI_SUCCESS (status)) { /* Delete any return object (especially if implicit_return is enabled) */ @@ -347,9 +345,8 @@ acpi_rs_set_srs_method_data ( } } - /* - * Clean up and return the status from acpi_ns_evaluate_relative - */ + /* Clean up and return the status from acpi_ns_evaluate_relative */ + acpi_ut_remove_reference (params[0]); return_ACPI_STATUS (status); } diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index a9cdcbeb343..83c944b8b09 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -49,6 +49,23 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME ("rsxface") +/* Local macros for 16,32-bit to 64-bit conversion */ + +#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) +#define ACPI_COPY_ADDRESS(out, in) \ + ACPI_COPY_FIELD(out, in, resource_type); \ + ACPI_COPY_FIELD(out, in, producer_consumer); \ + ACPI_COPY_FIELD(out, in, decode); \ + ACPI_COPY_FIELD(out, in, min_address_fixed); \ + ACPI_COPY_FIELD(out, in, max_address_fixed); \ + ACPI_COPY_FIELD(out, in, attribute); \ + ACPI_COPY_FIELD(out, in, granularity); \ + ACPI_COPY_FIELD(out, in, min_address_range); \ + ACPI_COPY_FIELD(out, in, max_address_range); \ + ACPI_COPY_FIELD(out, in, address_translation_offset); \ + ACPI_COPY_FIELD(out, in, address_length); \ + ACPI_COPY_FIELD(out, in, resource_source); + /******************************************************************************* * @@ -180,6 +197,7 @@ EXPORT_SYMBOL(acpi_get_current_resources); * and the value of ret_buffer is undefined. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_possible_resources ( @@ -346,9 +364,8 @@ acpi_set_current_resources ( ACPI_FUNCTION_TRACE ("acpi_set_current_resources"); - /* - * Must have a valid handle and buffer - */ + /* Must have a valid handle and buffer */ + if ((!device_handle) || (!in_buffer) || (!in_buffer->pointer) || @@ -362,21 +379,6 @@ acpi_set_current_resources ( EXPORT_SYMBOL(acpi_set_current_resources); -#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) -#define ACPI_COPY_ADDRESS(out, in) \ - ACPI_COPY_FIELD(out, in, resource_type); \ - ACPI_COPY_FIELD(out, in, producer_consumer); \ - ACPI_COPY_FIELD(out, in, decode); \ - ACPI_COPY_FIELD(out, in, min_address_fixed); \ - ACPI_COPY_FIELD(out, in, max_address_fixed); \ - ACPI_COPY_FIELD(out, in, attribute); \ - ACPI_COPY_FIELD(out, in, granularity); \ - ACPI_COPY_FIELD(out, in, min_address_range); \ - ACPI_COPY_FIELD(out, in, max_address_range); \ - ACPI_COPY_FIELD(out, in, address_translation_offset); \ - ACPI_COPY_FIELD(out, in, address_length); \ - ACPI_COPY_FIELD(out, in, resource_source); - /****************************************************************************** * * FUNCTION: acpi_resource_to_address64 @@ -408,14 +410,14 @@ acpi_resource_to_address64 ( case ACPI_RSTYPE_ADDRESS16: address16 = (struct acpi_resource_address16 *) &resource->data; - ACPI_COPY_ADDRESS(out, address16); + ACPI_COPY_ADDRESS (out, address16); break; case ACPI_RSTYPE_ADDRESS32: address32 = (struct acpi_resource_address32 *) &resource->data; - ACPI_COPY_ADDRESS(out, address32); + ACPI_COPY_ADDRESS (out, address32); break; @@ -434,4 +436,3 @@ acpi_resource_to_address64 ( return (AE_OK); } EXPORT_SYMBOL(acpi_resource_to_address64); - diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 334327c1f66..92e0c31539b 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -50,6 +50,24 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbconvrt") +/* Local prototypes */ + +static void +acpi_tb_init_generic_address ( + struct acpi_generic_address *new_gas_struct, + u8 register_bit_width, + acpi_physical_address address); + +static void +acpi_tb_convert_fadt1 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev1 *original_fadt); + +static void +acpi_tb_convert_fadt2 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev2 *original_fadt); + u8 acpi_fadt_is_v1; EXPORT_SYMBOL(acpi_fadt_is_v1); @@ -142,11 +160,13 @@ acpi_tb_convert_to_xsdt ( for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { if (acpi_gbl_RSDP->revision < 2) { ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], - (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]); + (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, + table_info->pointer))->table_offset_entry[i]); } else { new_table->table_offset_entry[i] = - (ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i]; + (ACPI_CAST_PTR (XSDT_DESCRIPTOR, + table_info->pointer))->table_offset_entry[i]; } } @@ -164,7 +184,7 @@ acpi_tb_convert_to_xsdt ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_tb_init_generic_address * @@ -201,7 +221,7 @@ acpi_tb_init_generic_address ( * PARAMETERS: local_fadt - Pointer to new FADT * original_fadt - Pointer to old FADT * - * RETURN: Populates local_fadt + * RETURN: None, populates local_fadt * * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format * @@ -213,7 +233,6 @@ acpi_tb_convert_fadt1 ( struct fadt_descriptor_rev1 *original_fadt) { - /* ACPI 1.0 FACS */ /* The BIOS stored FADT should agree with Revision 1.0 */ acpi_fadt_is_v1 = 1; @@ -232,7 +251,8 @@ acpi_tb_convert_fadt1 ( ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); /* - * System Interrupt Model isn't used in ACPI 2.0 (local_fadt->Reserved1 = 0;) + * System Interrupt Model isn't used in ACPI 2.0 + * (local_fadt->Reserved1 = 0;) */ /* @@ -269,7 +289,8 @@ acpi_tb_convert_fadt1 ( * that immediately follows. */ ACPI_MEMCPY (&local_fadt->reset_register, - &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register, + &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, + original_fadt))->reset_register, sizeof (struct acpi_generic_address) + 1); } else { @@ -304,7 +325,8 @@ acpi_tb_convert_fadt1 ( acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); /* PM1B is optional; leave null if not present */ @@ -312,7 +334,8 @@ acpi_tb_convert_fadt1 ( if (local_fadt->xpm1b_evt_blk.address) { acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1b_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); } } @@ -325,7 +348,7 @@ acpi_tb_convert_fadt1 ( * PARAMETERS: local_fadt - Pointer to new FADT * original_fadt - Pointer to old FADT * - * RETURN: Populates local_fadt + * RETURN: None, populates local_fadt * * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. * Handles optional "X" fields. @@ -348,7 +371,8 @@ acpi_tb_convert_fadt2 ( * is zero. */ if (!(local_fadt->xfirmware_ctrl)) { - ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, + local_fadt->V1_firmware_ctrl); } if (!(local_fadt->Xdsdt)) { @@ -357,32 +381,38 @@ acpi_tb_convert_fadt2 ( if (!(local_fadt->xpm1a_evt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); + local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); } if (!(local_fadt->xpm1b_evt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); + local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); } if (!(local_fadt->xpm1a_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); + local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); } if (!(local_fadt->xpm1b_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); + local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); } if (!(local_fadt->xpm2_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); + local_fadt->pm2_cnt_len, + (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); } if (!(local_fadt->xpm_tmr_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, (acpi_physical_address) local_fadt->V1_pm_tmr_blk); + local_fadt->pm_tm_len, + (acpi_physical_address) local_fadt->V1_pm_tmr_blk); } if (!(local_fadt->xgpe0_blk.address)) { @@ -399,18 +429,24 @@ acpi_tb_convert_fadt2 ( acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id; + + acpi_gbl_xpm1a_enable.address_space_id = + local_fadt->xpm1a_evt_blk.address_space_id; /* PM1B is optional; leave null if not present */ if (local_fadt->xpm1b_evt_blk.address) { acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1b_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + + acpi_gbl_xpm1b_enable.address_space_id = + local_fadt->xpm1b_evt_blk.address_space_id; } } @@ -432,7 +468,8 @@ acpi_tb_convert_fadt2 ( ******************************************************************************/ acpi_status -acpi_tb_convert_table_fadt (void) +acpi_tb_convert_table_fadt ( + void) { struct fadt_descriptor_rev2 *local_fadt; struct acpi_table_desc *table_desc; @@ -446,7 +483,8 @@ acpi_tb_convert_table_fadt (void) * at least as long as the version 1.0 FADT */ if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) { - ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", acpi_gbl_FADT->length)); + ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", + acpi_gbl_FADT->length)); return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } @@ -461,8 +499,9 @@ acpi_tb_convert_table_fadt (void) if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) { /* Length is too short to be a V2.0 table */ - ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", - acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); + ACPI_REPORT_WARNING (( + "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", + acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); } @@ -478,9 +517,8 @@ acpi_tb_convert_table_fadt (void) acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); } - /* - * Global FADT pointer will point to the new common V2.0 FADT - */ + /* Global FADT pointer will point to the new common V2.0 FADT */ + acpi_gbl_FADT = local_fadt; acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR); @@ -508,7 +546,7 @@ acpi_tb_convert_table_fadt (void) /******************************************************************************* * - * FUNCTION: acpi_tb_convert_table_facs + * FUNCTION: acpi_tb_build_common_facs * * PARAMETERS: table_info - Info for currently installed FACS * @@ -530,12 +568,14 @@ acpi_tb_build_common_facs ( /* Absolute minimum length is 24, but the ACPI spec says 64 */ if (acpi_gbl_FACS->length < 24) { - ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length)); + ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", + acpi_gbl_FACS->length)); return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } if (acpi_gbl_FACS->length < 64) { - ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", + ACPI_REPORT_WARNING (( + "FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", acpi_gbl_FACS->length)); } @@ -548,7 +588,8 @@ acpi_tb_build_common_facs ( (!(acpi_gbl_FACS->xfirmware_waking_vector))) { /* ACPI 1.0 FACS or short table or optional X_ field is zero */ - acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector)); + acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, + &(acpi_gbl_FACS->firmware_waking_vector)); acpi_gbl_common_fACS.vector_width = 32; } else { diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 896f3ddda62..4ab2aadc613 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -49,6 +49,19 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbget") +/* Local prototypes */ + +static acpi_status +acpi_tb_get_this_table ( + struct acpi_pointer *address, + struct acpi_table_header *header, + struct acpi_table_desc *table_info); + +static acpi_status +acpi_tb_table_override ( + struct acpi_table_header *header, + struct acpi_table_desc *table_info); + /******************************************************************************* * @@ -76,9 +89,8 @@ acpi_tb_get_table ( ACPI_FUNCTION_TRACE ("tb_get_table"); - /* - * Get the header in order to get signature and table size - */ + /* Get the header in order to get signature and table size */ + status = acpi_tb_get_table_header (address, &header); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -127,8 +139,8 @@ acpi_tb_get_table_header ( /* - * Flags contains the current processor mode (Virtual or Physical addressing) - * The pointer_type is either Logical or Physical + * Flags contains the current processor mode (Virtual or Physical + * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: @@ -136,7 +148,8 @@ acpi_tb_get_table_header ( /* Pointer matches processor mode, copy the header */ - ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header)); + ACPI_MEMCPY (return_header, address->pointer.logical, + sizeof (struct acpi_table_header)); break; @@ -144,10 +157,11 @@ acpi_tb_get_table_header ( /* Create a logical address for the physical pointer*/ - status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header), - (void *) &header); + status = acpi_os_map_memory (address->pointer.physical, + sizeof (struct acpi_table_header), (void *) &header); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", + ACPI_REPORT_ERROR (( + "Could not map memory at %8.8X%8.8X for length %X\n", ACPI_FORMAT_UINT64 (address->pointer.physical), sizeof (struct acpi_table_header))); return_ACPI_STATUS (status); @@ -210,9 +224,8 @@ acpi_tb_get_table_body ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Attempt table override. - */ + /* Attempt table override. */ + status = acpi_tb_table_override (header, table_info); if (ACPI_SUCCESS (status)) { /* Table was overridden by the host OS */ @@ -241,7 +254,7 @@ acpi_tb_get_table_body ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_table_override ( struct acpi_table_header *header, struct acpi_table_desc *table_info) @@ -315,7 +328,7 @@ acpi_tb_table_override ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_this_table ( struct acpi_pointer *address, struct acpi_table_header *header, @@ -330,8 +343,8 @@ acpi_tb_get_this_table ( /* - * Flags contains the current processor mode (Virtual or Physical addressing) - * The pointer_type is either Logical or Physical + * Flags contains the current processor mode (Virtual or Physical + * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: @@ -341,7 +354,8 @@ acpi_tb_get_this_table ( full_table = ACPI_MEM_ALLOCATE (header->length); if (!full_table) { - ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n", + ACPI_REPORT_ERROR (( + "Could not allocate table memory for [%4.4s] length %X\n", header->signature, header->length)); return_ACPI_STATUS (AE_NO_MEMORY); } @@ -362,12 +376,14 @@ acpi_tb_get_this_table ( * Just map the table's physical memory * into our address space. */ - status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length, - (void *) &full_table); + status = acpi_os_map_memory (address->pointer.physical, + (acpi_size) header->length, (void *) &full_table); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", + ACPI_REPORT_ERROR (( + "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", header->signature, - ACPI_FORMAT_UINT64 (address->pointer.physical), header->length)); + ACPI_FORMAT_UINT64 (address->pointer.physical), + header->length)); return (status); } @@ -465,9 +481,8 @@ acpi_tb_get_table_ptr ( return_ACPI_STATUS (AE_OK); } - /* - * Check for instance out of range - */ + /* Check for instance out of range */ + if (instance > acpi_gbl_table_lists[table_type].count) { return_ACPI_STATUS (AE_NOT_EXIST); } diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c index adc4270988b..eea5b8cb5eb 100644 --- a/drivers/acpi/tables/tbgetall.c +++ b/drivers/acpi/tables/tbgetall.c @@ -49,6 +49,19 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbgetall") +/* Local prototypes */ + +static acpi_status +acpi_tb_get_primary_table ( + struct acpi_pointer *address, + struct acpi_table_desc *table_info); + +static acpi_status +acpi_tb_get_secondary_table ( + struct acpi_pointer *address, + acpi_string signature, + struct acpi_table_desc *table_info); + /******************************************************************************* * @@ -63,7 +76,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_primary_table ( struct acpi_pointer *address, struct acpi_table_desc *table_info) @@ -81,9 +94,8 @@ acpi_tb_get_primary_table ( return_ACPI_STATUS (AE_OK); } - /* - * Get the header in order to get signature and table size - */ + /* Get the header in order to get signature and table size */ + status = acpi_tb_get_table_header (address, &header); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -130,7 +142,7 @@ acpi_tb_get_primary_table ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_secondary_table ( struct acpi_pointer *address, acpi_string signature, @@ -153,7 +165,8 @@ acpi_tb_get_secondary_table ( /* Signature must match request */ if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { - ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n", + ACPI_REPORT_ERROR (( + "Incorrect table signature - wanted [%s] found [%4.4s]\n", signature, header.signature)); return_ACPI_STATUS (AE_BAD_SIGNATURE); } @@ -230,7 +243,8 @@ acpi_tb_get_required_tables ( for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { /* Get the table address from the common internal XSDT */ - address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; + address.pointer.value = + acpi_gbl_XSDT->table_offset_entry[i]; /* * Get the tables needed by this subsystem (FADT and any SSDTs). @@ -252,18 +266,18 @@ acpi_tb_get_required_tables ( } /* - * Convert the FADT to a common format. This allows earlier revisions of the - * table to coexist with newer versions, using common access code. + * Convert the FADT to a common format. This allows earlier revisions of + * the table to coexist with newer versions, using common access code. */ status = acpi_tb_convert_table_fadt (); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n")); + ACPI_REPORT_ERROR (( + "Could not convert FADT to internal common format\n")); return_ACPI_STATUS (status); } - /* - * Get the FACS (Pointed to by the FADT) - */ + /* Get the FACS (Pointed to by the FADT) */ + address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl; status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info); @@ -282,9 +296,8 @@ acpi_tb_get_required_tables ( return_ACPI_STATUS (status); } - /* - * Get/install the DSDT (Pointed to by the FADT) - */ + /* Get/install the DSDT (Pointed to by the FADT) */ + address.pointer.value = acpi_gbl_FADT->Xdsdt; status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info); diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 85d5bb01022..629b64c8193 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -49,6 +49,14 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbinstal") +/* Local prototypes */ + +static acpi_status +acpi_tb_match_signature ( + char *signature, + struct acpi_table_desc *table_info, + u8 search_type); + /******************************************************************************* * @@ -56,6 +64,7 @@ * * PARAMETERS: Signature - Table signature to match * table_info - Return data + * search_type - Table type to match (primary/secondary) * * RETURN: Status * @@ -64,7 +73,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_match_signature ( char *signature, struct acpi_table_desc *table_info, @@ -76,9 +85,8 @@ acpi_tb_match_signature ( ACPI_FUNCTION_TRACE ("tb_match_signature"); - /* - * Search for a signature match among the known table types - */ + /* Search for a signature match among the known table types */ + for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { if (!(acpi_gbl_table_data[i].flags & search_type)) { continue; @@ -161,6 +169,7 @@ acpi_tb_install_table ( * FUNCTION: acpi_tb_recognize_table * * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * search_type - Table type to match (primary/secondary) * * RETURN: Status * @@ -203,7 +212,8 @@ acpi_tb_recognize_table ( * This can be any one of many valid ACPI tables, it just isn't one of * the tables that is consumed by the core subsystem */ - status = acpi_tb_match_signature (table_header->signature, table_info, search_type); + status = acpi_tb_match_signature (table_header->signature, + table_info, search_type); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -253,9 +263,8 @@ acpi_tb_init_table_descriptor ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Install the table into the global data structure - */ + /* Install the table into the global data structure */ + list_head = &acpi_gbl_table_lists[table_type]; /* @@ -316,7 +325,8 @@ acpi_tb_init_table_descriptor ( table_desc->aml_start = (u8 *) (table_desc->pointer + 1), table_desc->aml_length = (u32) (table_desc->length - (u32) sizeof (struct acpi_table_header)); - table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE); + table_desc->table_id = acpi_ut_allocate_owner_id ( + ACPI_OWNER_TYPE_TABLE); table_desc->loaded_into_namespace = FALSE; /* @@ -349,7 +359,8 @@ acpi_tb_init_table_descriptor ( ******************************************************************************/ void -acpi_tb_delete_all_tables (void) +acpi_tb_delete_all_tables ( + void) { acpi_table_type type; diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 9c6913238d5..b7ffe39c362 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -84,8 +84,9 @@ acpi_tb_verify_rsdp ( /* * Obtain access to the RSDP structure */ - status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor), - (void *) &rsdp); + status = acpi_os_map_memory (address->pointer.physical, + sizeof (struct rsdp_descriptor), + (void *) &rsdp); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -154,9 +155,9 @@ cleanup: * * FUNCTION: acpi_tb_get_rsdt_address * - * PARAMETERS: None + * PARAMETERS: out_address - Where the address is returned * - * RETURN: RSDT physical address + * RETURN: None, Address * * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the * version of the RSDP @@ -181,7 +182,8 @@ acpi_tb_get_rsdt_address ( out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address; } else { - out_address->pointer.value = acpi_gbl_RSDP->xsdt_physical_address; + out_address->pointer.value = + acpi_gbl_RSDP->xsdt_physical_address; } } @@ -224,7 +226,8 @@ acpi_tb_validate_rsdt ( if (no_match) { /* Invalid RSDT or XSDT signature */ - ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); + ACPI_REPORT_ERROR (( + "Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20); @@ -282,6 +285,7 @@ acpi_tb_get_table_rsdt ( if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n", acpi_format_exception (status))); + return_ACPI_STATUS (status); } @@ -299,7 +303,8 @@ acpi_tb_get_table_rsdt ( /* Get the number of tables defined in the RSDT or XSDT */ - acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer); + acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, + table_info.pointer); /* Convert and/or copy to an XSDT structure */ diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index fede5804c78..e69d01d443d 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -49,48 +49,14 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbutils") +/* Local prototypes */ -/******************************************************************************* - * - * FUNCTION: acpi_tb_handle_to_object - * - * PARAMETERS: table_id - Id for which the function is searching - * table_desc - Pointer to return the matching table - * descriptor. - * - * RETURN: Search the tables to find one with a matching table_id and - * return a pointer to that table descriptor. - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE +#ifdef ACPI_OBSOLETE_FUNCTIONS acpi_status acpi_tb_handle_to_object ( u16 table_id, - struct acpi_table_desc **return_table_desc) -{ - u32 i; - struct acpi_table_desc *table_desc; - - - ACPI_FUNCTION_NAME ("tb_handle_to_object"); - - - for (i = 0; i < ACPI_TABLE_MAX; i++) { - table_desc = acpi_gbl_table_lists[i].next; - while (table_desc) { - if (table_desc->table_id == table_id) { - *return_table_desc = table_desc; - return (AE_OK); - } - - table_desc = table_desc->next; - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id)); - return (AE_BAD_PARAMETER); -} -#endif /* ACPI_FUTURE_USAGE */ + struct acpi_table_desc **table_desc); +#endif /******************************************************************************* @@ -128,6 +94,7 @@ acpi_tb_validate_table_header ( if (!acpi_os_readable (table_header, sizeof (struct acpi_table_header))) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Cannot read table header at %p\n", table_header)); + return (AE_BAD_ADDRESS); } @@ -141,6 +108,7 @@ acpi_tb_validate_table_header ( ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", (char *) &signature)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); return (AE_BAD_SIGNATURE); } @@ -154,6 +122,7 @@ acpi_tb_validate_table_header ( ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n", (u32) table_header->length)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); return (AE_BAD_HEADER); } @@ -193,8 +162,10 @@ acpi_tb_verify_table_checksum ( /* Return the appropriate exception */ if (checksum) { - ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", - table_header->signature, (u32) table_header->checksum, (u32) checksum)); + ACPI_REPORT_WARNING (( + "Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", + table_header->signature, (u32) table_header->checksum, + (u32) checksum)); status = AE_BAD_CHECKSUM; } @@ -209,7 +180,7 @@ acpi_tb_verify_table_checksum ( * PARAMETERS: Buffer - Buffer to checksum * Length - Size of the buffer * - * RETURNS 8 bit checksum of buffer + * RETURN: 8 bit checksum of buffer * * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it. * @@ -238,3 +209,47 @@ acpi_tb_checksum ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_tb_handle_to_object + * + * PARAMETERS: table_id - Id for which the function is searching + * table_desc - Pointer to return the matching table + * descriptor. + * + * RETURN: Search the tables to find one with a matching table_id and + * return a pointer to that table descriptor. + * + ******************************************************************************/ + +acpi_status +acpi_tb_handle_to_object ( + u16 table_id, + struct acpi_table_desc **return_table_desc) +{ + u32 i; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_NAME ("tb_handle_to_object"); + + + for (i = 0; i < ACPI_TABLE_MAX; i++) { + table_desc = acpi_gbl_table_lists[i].next; + while (table_desc) { + if (table_desc->table_id == table_id) { + *return_table_desc = table_desc; + return (AE_OK); + } + + table_desc = table_desc->next; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id)); + return (AE_BAD_PARAMETER); +} +#endif + + diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 7715043461c..0c0b9085dbe 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -67,7 +67,8 @@ ******************************************************************************/ acpi_status -acpi_load_tables (void) +acpi_load_tables ( + void) { struct acpi_pointer rsdp_address; acpi_status status; @@ -82,7 +83,7 @@ acpi_load_tables (void) &rsdp_address); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not get RSDP, %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -93,7 +94,7 @@ acpi_load_tables (void) status = acpi_tb_verify_rsdp (&rsdp_address); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: RSDP Failed validation: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -102,7 +103,7 @@ acpi_load_tables (void) status = acpi_tb_get_table_rsdt (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not load RSDT: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -110,20 +111,20 @@ acpi_load_tables (void) status = acpi_tb_get_required_tables (); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", - acpi_format_exception (status))); + ACPI_REPORT_ERROR (( + "acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", + acpi_format_exception (status))); goto error_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); - /* Load the namespace from the tables */ status = acpi_ns_load_namespace (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not load namespace: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -139,7 +140,6 @@ error_exit: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_load_table @@ -250,7 +250,6 @@ acpi_unload_table ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Find all tables of the requested type */ table_desc = acpi_gbl_table_lists[table_type].next; @@ -321,7 +320,6 @@ acpi_get_table_header ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); @@ -329,23 +327,20 @@ acpi_get_table_header ( return_ACPI_STATUS (status); } - /* - * The function will return a NULL pointer if the table is not loaded - */ + /* The function will return a NULL pointer if the table is not loaded */ + if (tbl_ptr == NULL) { return_ACPI_STATUS (AE_NOT_EXIST); } - /* - * Copy the header to the caller's buffer - */ + /* Copy the header to the caller's buffer */ + ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr, - sizeof (struct acpi_table_header)); + sizeof (struct acpi_table_header)); return_ACPI_STATUS (status); } - #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -404,7 +399,6 @@ acpi_get_table ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); @@ -423,9 +417,8 @@ acpi_get_table ( /* Get the table length */ if (table_type == ACPI_TABLE_RSDP) { - /* - * RSD PTR is the only "table" without a header - */ + /* RSD PTR is the only "table" without a header */ + table_length = sizeof (struct rsdp_descriptor); } else { diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 6e8072ebbac..dc3c3f6a9f6 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -50,6 +50,18 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbxfroot") +/* Local prototypes */ + +static acpi_status +acpi_tb_find_rsdp ( + struct acpi_table_desc *table_info, + u32 flags); + +static u8 * +acpi_tb_scan_memory_for_rsdp ( + u8 *start_address, + u32 length); + /******************************************************************************* * @@ -57,7 +69,8 @@ * * PARAMETERS: Signature - String with ACPI table signature * oem_id - String with the table OEM ID - * oem_table_id - String with the OEM Table ID. + * oem_table_id - String with the OEM Table ID + * table_ptr - Where the table pointer is returned * * RETURN: Status * @@ -99,14 +112,13 @@ acpi_tb_find_table ( if (!acpi_gbl_DSDT) { return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - table = acpi_gbl_DSDT; } else { /* Find the table */ status = acpi_get_firmware_table (signature, 1, - ACPI_LOGICAL_ADDRESSING, &table); + ACPI_LOGICAL_ADDRESSING, &table); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -114,14 +126,19 @@ acpi_tb_find_table ( /* Check oem_id and oem_table_id */ - if ((oem_id[0] && ACPI_STRNCMP ( - oem_id, table->oem_id, sizeof (table->oem_id))) || + if ((oem_id[0] && ACPI_STRNCMP ( + oem_id, table->oem_id, + sizeof (table->oem_id))) || + (oem_table_id[0] && ACPI_STRNCMP ( - oem_table_id, table->oem_table_id, sizeof (table->oem_table_id)))) { + oem_table_id, table->oem_table_id, + sizeof (table->oem_table_id)))) { return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND); } - ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature)); + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", + table->signature)); + *table_ptr = table; return_ACPI_STATUS (AE_OK); } @@ -191,8 +208,8 @@ acpi_get_firmware_table ( /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor), - (void *) &acpi_gbl_RSDP); + status = acpi_os_map_memory (address.pointer.physical, + sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -203,7 +220,8 @@ acpi_get_firmware_table ( /* The signature and checksum must both be correct */ - if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, + sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ return_ACPI_STATUS (AE_BAD_SIGNATURE); @@ -313,7 +331,8 @@ acpi_get_firmware_table ( cleanup: - acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); + acpi_os_unmap_memory (rsdt_info->pointer, + (acpi_size) rsdt_info->pointer->length); ACPI_MEM_FREE (rsdt_info); if (header) { @@ -335,8 +354,8 @@ EXPORT_SYMBOL(acpi_get_firmware_table); * * FUNCTION: acpi_find_root_pointer * - * PARAMETERS: **rsdp_address - Where to place the RSDP address - * Flags - Logical/Physical addressing + * PARAMETERS: Flags - Logical/Physical addressing + * rsdp_address - Where to place the RSDP address * * RETURN: Status, Physical address of the RSDP * @@ -363,6 +382,7 @@ acpi_find_root_pointer ( ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "RSDP structure not found, %s Flags=%X\n", acpi_format_exception (status), flags)); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); } @@ -385,7 +405,7 @@ acpi_find_root_pointer ( * ******************************************************************************/ -u8 * +static u8 * acpi_tb_scan_memory_for_rsdp ( u8 *start_address, u32 length) @@ -406,7 +426,8 @@ acpi_tb_scan_memory_for_rsdp ( mem_rover += ACPI_RSDP_SCAN_STEP) { /* The signature and checksum must both be correct */ - if (ACPI_STRNCMP ((char *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (ACPI_STRNCMP ((char *) mem_rover, + RSDP_SIG, sizeof (RSDP_SIG) - 1) != 0) { /* No signature match, keep looking */ continue; @@ -450,7 +471,7 @@ acpi_tb_scan_memory_for_rsdp ( * * FUNCTION: acpi_tb_find_rsdp * - * PARAMETERS: *table_info - Where the table info is returned + * PARAMETERS: table_info - Where the table info is returned * Flags - Current memory mode (logical vs. * physical addressing) * @@ -468,7 +489,7 @@ acpi_tb_scan_memory_for_rsdp ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_find_rsdp ( struct acpi_table_desc *table_info, u32 flags) @@ -483,43 +504,49 @@ acpi_tb_find_rsdp ( /* - * Scan supports either 1) Logical addressing or 2) Physical addressing + * Scan supports either logical addressing or physical addressing */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - /* - * 1a) Get the location of the EBDA - */ - status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH, - (void *) &table_ptr); + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ + + status = acpi_os_map_memory ( + (acpi_physical_address) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); + return_ACPI_STATUS (status); } ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); - physical_address <<= 4; /* Convert segment to physical address */ + + /* Convert segment part to physical address */ + + physical_address <<= 4; acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); /* EBDA present? */ if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + * 1b) Search EBDA paragraphs (EBDa is required to be a + * minimum of 1_k length) */ - status = acpi_os_map_memory ((acpi_physical_address) physical_address, - ACPI_EBDA_WINDOW_SIZE, - (void *) &table_ptr); + status = acpi_os_map_memory ( + (acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); } - mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, + ACPI_EBDA_WINDOW_SIZE); acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { @@ -527,7 +554,8 @@ acpi_tb_find_rsdp ( physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = (acpi_physical_address) physical_address; + table_info->physical_address = + (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -535,13 +563,15 @@ acpi_tb_find_rsdp ( /* * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE, - (void *) &table_ptr); + status = acpi_os_map_memory ( + (acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); + if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); + return_ACPI_STATUS (status); } @@ -551,9 +581,11 @@ acpi_tb_find_rsdp ( if (mem_rover) { /* Found it, return the physical address */ - physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); + physical_address = + ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = (acpi_physical_address) physical_address; + table_info->physical_address = + (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -562,9 +594,8 @@ acpi_tb_find_rsdp ( * Physical addressing */ else { - /* - * 1a) Get the location of the EBDA - */ + /* 1a) Get the location of the EBDA */ + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); physical_address <<= 4; /* Convert segment to physical address */ @@ -572,9 +603,11 @@ acpi_tb_find_rsdp ( if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of + * 1_k length) */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + mem_rover = acpi_tb_scan_memory_for_rsdp ( + ACPI_PHYSADDR_TO_PTR (physical_address), ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ @@ -584,10 +617,10 @@ acpi_tb_find_rsdp ( } } - /* - * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh - */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), + /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ + + mem_rover = acpi_tb_scan_memory_for_rsdp ( + ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 3313439c4bc..c4e7f989a2b 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -47,8 +47,35 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utalloc") +/* Local prototypes */ -/****************************************************************************** +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +static struct acpi_debug_mem_block * +acpi_ut_find_allocation ( + u32 list_id, + void *allocation); + +static acpi_status +acpi_ut_track_allocation ( + u32 list_id, + struct acpi_debug_mem_block *address, + acpi_size size, + u8 alloc_type, + u32 component, + char *module, + u32 line); + +static acpi_status +acpi_ut_remove_allocation ( + u32 list_id, + struct acpi_debug_mem_block *address, + u32 component, + char *module, + u32 line); +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + + +/******************************************************************************* * * FUNCTION: acpi_ut_release_to_cache * @@ -98,7 +125,8 @@ acpi_ut_release_to_cache ( /* Put the object at the head of the cache list */ - * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; + * (ACPI_CAST_INDIRECT_PTR (char, + &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; cache_info->list_head = object; cache_info->cache_depth++; @@ -115,7 +143,7 @@ acpi_ut_release_to_cache ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_acquire_from_cache * @@ -156,7 +184,8 @@ acpi_ut_acquire_from_cache ( /* There is an object available, use it */ object = cache_info->list_head; - cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))); + cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, + &(((char *) object)[cache_info->link_offset]))); ACPI_MEM_TRACKING (cache_info->cache_hits++); cache_info->cache_depth--; @@ -201,7 +230,7 @@ acpi_ut_acquire_from_cache ( #ifdef ACPI_ENABLE_OBJECT_CACHE -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_delete_generic_cache * @@ -228,7 +257,8 @@ acpi_ut_delete_generic_cache ( while (cache_info->list_head) { /* Delete one cached state object */ - next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset]))); + next = *(ACPI_CAST_INDIRECT_PTR (char, + &(((char *) cache_info->list_head)[cache_info->link_offset]))); ACPI_MEM_FREE (cache_info->list_head); cache_info->list_head = next; @@ -497,8 +527,8 @@ acpi_ut_allocate_and_track ( acpi_status status; - allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component, - module, line); + allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), + component, module, line); if (!allocation) { return (NULL); } @@ -543,8 +573,8 @@ acpi_ut_callocate_and_track ( acpi_status status; - allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component, - module, line); + allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), + component, module, line); if (!allocation) { /* Report allocation error */ @@ -637,7 +667,7 @@ acpi_ut_free_and_track ( * ******************************************************************************/ -struct acpi_debug_mem_block * +static struct acpi_debug_mem_block * acpi_ut_find_allocation ( u32 list_id, void *allocation) @@ -686,7 +716,7 @@ acpi_ut_find_allocation ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_track_allocation ( u32 list_id, struct acpi_debug_mem_block *allocation, @@ -721,10 +751,12 @@ acpi_ut_track_allocation ( element = acpi_ut_find_allocation (list_id, allocation); if (element) { - ACPI_REPORT_ERROR (("ut_track_allocation: Allocation already present in list! (%p)\n", + ACPI_REPORT_ERROR (( + "ut_track_allocation: Allocation already present in list! (%p)\n", allocation)); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", + element, allocation)); goto unlock_and_exit; } @@ -773,7 +805,7 @@ unlock_and_exit: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_remove_allocation ( u32 list_id, struct acpi_debug_mem_block *allocation, @@ -797,7 +829,7 @@ acpi_ut_remove_allocation ( /* No allocations! */ _ACPI_REPORT_ERROR (module, line, component, - ("ut_remove_allocation: Empty allocation list, nothing to free!\n")); + ("ut_remove_allocation: Empty allocation list, nothing to free!\n")); return_ACPI_STATUS (AE_OK); } @@ -824,7 +856,8 @@ acpi_ut_remove_allocation ( ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size); - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", + allocation->size)); status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); return_ACPI_STATUS (status); @@ -842,6 +875,7 @@ acpi_ut_remove_allocation ( * DESCRIPTION: Print some info about the outstanding allocations. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE void acpi_ut_dump_allocation_info ( @@ -884,7 +918,8 @@ acpi_ut_dump_allocation_info ( ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, ("%30s: %4d (%3d Kb)\n", "Max Nodes", acpi_gbl_max_concurrent_node_count, - ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * sizeof (struct acpi_namespace_node))))); + ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * + sizeof (struct acpi_namespace_node))))); */ return_VOID; } @@ -933,26 +968,26 @@ acpi_ut_dump_allocations ( descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space); if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ", - descriptor, element->size, element->module, - element->line, acpi_ut_get_descriptor_name (descriptor)); + descriptor, element->size, element->module, + element->line, acpi_ut_get_descriptor_name (descriptor)); /* Most of the elements will be Operand objects. */ switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) { case ACPI_DESC_TYPE_OPERAND: acpi_os_printf ("%12.12s R%hd", - acpi_ut_get_type_name (descriptor->object.common.type), - descriptor->object.common.reference_count); + acpi_ut_get_type_name (descriptor->object.common.type), + descriptor->object.common.reference_count); break; case ACPI_DESC_TYPE_PARSER: acpi_os_printf ("aml_opcode %04hX", - descriptor->op.asl.aml_opcode); + descriptor->op.asl.aml_opcode); break; case ACPI_DESC_TYPE_NAMED: acpi_os_printf ("%4.4s", - acpi_ut_get_node_name (&descriptor->node)); + acpi_ut_get_node_name (&descriptor->node)); break; default: @@ -983,6 +1018,5 @@ acpi_ut_dump_allocations ( return_VOID; } - #endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 0fcd98bde0d..11e88495716 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -49,21 +49,69 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utcopy") +/* Local prototypes */ + +static acpi_status +acpi_ut_copy_isimple_to_esimple ( + union acpi_operand_object *internal_object, + union acpi_object *external_object, + u8 *data_space, + acpi_size *buffer_space_used); + +static acpi_status +acpi_ut_copy_ielement_to_ielement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + +static acpi_status +acpi_ut_copy_ipackage_to_epackage ( + union acpi_operand_object *internal_object, + u8 *buffer, + acpi_size *space_used); + +static acpi_status +acpi_ut_copy_esimple_to_isimple( + union acpi_object *user_obj, + union acpi_operand_object **return_obj); + +static acpi_status +acpi_ut_copy_simple_object ( + union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc); + +static acpi_status +acpi_ut_copy_ielement_to_eelement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + +static acpi_status +acpi_ut_copy_ipackage_to_ipackage ( + union acpi_operand_object *source_obj, + union acpi_operand_object *dest_obj, + struct acpi_walk_state *walk_state); + /******************************************************************************* * * FUNCTION: acpi_ut_copy_isimple_to_esimple * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *Buffer - Where the object is returned - * *space_used - Where the data length is returned + * PARAMETERS: internal_object - Source object to be copied + * external_object - Where to return the copied object + * data_space - Where object data is returned (such as + * buffer and string data) + * buffer_space_used - Length of data_space that was used * * RETURN: Status * - * DESCRIPTION: This function is called to place a simple object in a user - * buffer. + * DESCRIPTION: This function is called to copy a simple internal object to + * an external object. * - * The buffer is assumed to have sufficient space for the object. + * The data_space buffer is assumed to have sufficient space for + * the object. * ******************************************************************************/ @@ -107,10 +155,12 @@ acpi_ut_copy_isimple_to_esimple ( external_object->string.pointer = (char *) data_space; external_object->string.length = internal_object->string.length; - *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((acpi_size) internal_object->string.length + 1); + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (acpi_size) internal_object->string.length + 1); - ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, - (acpi_size) internal_object->string.length + 1); + ACPI_MEMCPY ((void *) data_space, + (void *) internal_object->string.pointer, + (acpi_size) internal_object->string.length + 1); break; @@ -118,10 +168,12 @@ acpi_ut_copy_isimple_to_esimple ( external_object->buffer.pointer = data_space; external_object->buffer.length = internal_object->buffer.length; - *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length); + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ( + internal_object->string.length); - ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, - internal_object->buffer.length); + ACPI_MEMCPY ((void *) data_space, + (void *) internal_object->buffer.pointer, + internal_object->buffer.length); break; @@ -194,7 +246,7 @@ acpi_ut_copy_isimple_to_esimple ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ielement_to_eelement ( u8 object_type, union acpi_operand_object *source_object, @@ -213,7 +265,7 @@ acpi_ut_copy_ielement_to_eelement ( this_index = state->pkg.index; target_object = (union acpi_object *) - &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index]; + &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index]; switch (object_type) { case ACPI_COPY_TYPE_SIMPLE: @@ -236,7 +288,8 @@ acpi_ut_copy_ielement_to_eelement ( */ target_object->type = ACPI_TYPE_PACKAGE; target_object->package.count = source_object->package.count; - target_object->package.elements = ACPI_CAST_PTR (union acpi_object, info->free_space); + target_object->package.elements = + ACPI_CAST_PTR (union acpi_object, info->free_space); /* * Pass the new package object back to the package walk routine @@ -248,7 +301,8 @@ acpi_ut_copy_ielement_to_eelement ( * update the buffer length counter */ object_space = ACPI_ROUND_UP_TO_NATIVE_WORD ( - (acpi_size) target_object->package.count * sizeof (union acpi_object)); + (acpi_size) target_object->package.count * + sizeof (union acpi_object)); break; @@ -266,9 +320,9 @@ acpi_ut_copy_ielement_to_eelement ( * * FUNCTION: acpi_ut_copy_ipackage_to_epackage * - * PARAMETERS: *internal_object - Pointer to the object we are returning - * *Buffer - Where the object is returned - * *space_used - Where the object length is returned + * PARAMETERS: internal_object - Pointer to the object we are returning + * Buffer - Where the object is returned + * space_used - Where the object length is returned * * RETURN: Status * @@ -304,13 +358,15 @@ acpi_ut_copy_ipackage_to_epackage ( * Free space begins right after the first package */ info.length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); - info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD ( + sizeof (union acpi_object)); info.object_space = 0; info.num_packages = 1; external_object->type = ACPI_GET_OBJECT_TYPE (internal_object); external_object->package.count = internal_object->package.count; - external_object->package.elements = ACPI_CAST_PTR (union acpi_object, info.free_space); + external_object->package.elements = ACPI_CAST_PTR (union acpi_object, + info.free_space); /* * Leave room for an array of ACPI_OBJECTS in the buffer @@ -333,8 +389,8 @@ acpi_ut_copy_ipackage_to_epackage ( * * FUNCTION: acpi_ut_copy_iobject_to_eobject * - * PARAMETERS: *internal_object - The internal object to be converted - * *buffer_ptr - Where the object is returned + * PARAMETERS: internal_object - The internal object to be converted + * buffer_ptr - Where the object is returned * * RETURN: Status * @@ -367,10 +423,10 @@ acpi_ut_copy_iobject_to_eobject ( * Build a simple object (no nested objects) */ status = acpi_ut_copy_isimple_to_esimple (internal_object, - (union acpi_object *) ret_buffer->pointer, - ((u8 *) ret_buffer->pointer + - ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))), - &ret_buffer->length); + (union acpi_object *) ret_buffer->pointer, + ((u8 *) ret_buffer->pointer + + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))), + &ret_buffer->length); /* * build simple does not include the object size in the length * so we add it in here @@ -386,8 +442,8 @@ acpi_ut_copy_iobject_to_eobject ( * * FUNCTION: acpi_ut_copy_esimple_to_isimple * - * PARAMETERS: *external_object - The external object to be converted - * *internal_object - Where the internal object is returned + * PARAMETERS: external_object - The external object to be converted + * ret_internal_object - Where the internal object is returned * * RETURN: Status * @@ -398,7 +454,7 @@ acpi_ut_copy_iobject_to_eobject ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_esimple_to_isimple ( union acpi_object *external_object, union acpi_operand_object **ret_internal_object) @@ -417,7 +473,8 @@ acpi_ut_copy_esimple_to_isimple ( case ACPI_TYPE_BUFFER: case ACPI_TYPE_INTEGER: - internal_object = acpi_ut_create_internal_object ((u8) external_object->type); + internal_object = acpi_ut_create_internal_object ( + (u8) external_object->type); if (!internal_object) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -486,7 +543,6 @@ error_exit: #ifdef ACPI_FUTURE_IMPLEMENTATION - /* Code to convert packages that are parameters to control methods */ /******************************************************************************* @@ -614,7 +670,7 @@ acpi_ut_copy_eobject_to_iobject ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_simple_object ( union acpi_operand_object *source_desc, union acpi_operand_object *dest_desc) @@ -724,7 +780,7 @@ acpi_ut_copy_simple_object ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ielement_to_ielement ( u8 object_type, union acpi_operand_object *source_object, @@ -837,7 +893,7 @@ error_exit: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ipackage_to_ipackage ( union acpi_operand_object *source_obj, union acpi_operand_object *dest_obj, diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 985c5d045b7..794c7df3f2a 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -56,7 +56,7 @@ static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_init_stack_ptr_trace * @@ -64,9 +64,9 @@ static char *acpi_gbl_fn_exit_str = "----Exit-"; * * RETURN: None * - * DESCRIPTION: Save the current stack pointer + * DESCRIPTION: Save the current CPU stack pointer at subsystem startup * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_init_stack_ptr_trace ( @@ -79,7 +79,7 @@ acpi_ut_init_stack_ptr_trace ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_track_stack_ptr * @@ -87,9 +87,9 @@ acpi_ut_init_stack_ptr_trace ( * * RETURN: None * - * DESCRIPTION: Save the current stack pointer + * DESCRIPTION: Save the current CPU stack pointer * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_track_stack_ptr ( @@ -110,16 +110,16 @@ acpi_ut_track_stack_ptr ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_debug_print * - * PARAMETERS: debug_level - Requested debug print level - * proc_name - Caller's procedure name - * module_name - Caller's module name (for error output) + * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number (for error output) - * component_id - Caller's component ID (for error output) - * + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID * Format - Printf format field * ... - Optional printf arguments * @@ -128,7 +128,7 @@ acpi_ut_track_stack_ptr ( * DESCRIPTION: Print error message with prefix consisting of the module name, * line number, and component ID. * - ****************************************************************************/ + ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print ( @@ -157,7 +157,8 @@ acpi_ut_debug_print ( if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n", + acpi_os_printf ( + "\n**** Context Switch from TID %X to TID %X ****\n\n", acpi_gbl_prev_thread_id, thread_id); } @@ -174,15 +175,16 @@ acpi_ut_debug_print ( acpi_os_printf ("[%04lX] ", thread_id); } - acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); + acpi_os_printf ("[%02ld] %-22.22s: ", + acpi_gbl_nesting_level, dbg_info->proc_name); va_start (args, format); acpi_os_vprintf (format, args); } -EXPORT_SYMBOL(acpi_ut_debug_print); +EXPORT_SYMBOL(acpi_ut_debug_print); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_debug_print_raw * @@ -200,7 +202,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print); * DESCRIPTION: Print message with no headers. Has same interface as * debug_print so that the same macros can be used. * - ****************************************************************************/ + ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print_raw ( @@ -224,7 +226,7 @@ acpi_ut_debug_print_raw ( EXPORT_SYMBOL(acpi_ut_debug_print_raw); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace * @@ -239,7 +241,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print_raw); * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace ( @@ -256,7 +258,7 @@ acpi_ut_trace ( EXPORT_SYMBOL(acpi_ut_trace); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_ptr * @@ -272,7 +274,7 @@ EXPORT_SYMBOL(acpi_ut_trace); * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_ptr ( @@ -288,7 +290,7 @@ acpi_ut_trace_ptr ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_str * @@ -304,7 +306,7 @@ acpi_ut_trace_ptr ( * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_str ( @@ -321,7 +323,7 @@ acpi_ut_trace_str ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_u32 * @@ -337,7 +339,7 @@ acpi_ut_trace_str ( * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_u32 ( @@ -354,7 +356,7 @@ acpi_ut_trace_u32 ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_exit * @@ -369,7 +371,7 @@ acpi_ut_trace_u32 ( * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_exit ( @@ -385,7 +387,7 @@ acpi_ut_exit ( EXPORT_SYMBOL(acpi_ut_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_status_exit * @@ -401,7 +403,7 @@ EXPORT_SYMBOL(acpi_ut_exit); * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit status also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_status_exit ( @@ -426,7 +428,7 @@ acpi_ut_status_exit ( EXPORT_SYMBOL(acpi_ut_status_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_value_exit * @@ -442,7 +444,7 @@ EXPORT_SYMBOL(acpi_ut_status_exit); * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_value_exit ( @@ -460,7 +462,7 @@ acpi_ut_value_exit ( EXPORT_SYMBOL(acpi_ut_value_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_ptr_exit * @@ -469,14 +471,14 @@ EXPORT_SYMBOL(acpi_ut_value_exit); * proc_name - Caller's procedure name * module_name - Caller's module name * component_id - Caller's component ID - * Value - Value to be printed with exit msg + * Ptr - Pointer to display * * RETURN: None * * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_ptr_exit ( @@ -494,7 +496,7 @@ acpi_ut_ptr_exit ( #endif -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_dump_buffer * @@ -507,7 +509,7 @@ acpi_ut_ptr_exit ( * * DESCRIPTION: Generic dump buffer in both hex and ascii. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_dump_buffer ( @@ -533,34 +535,28 @@ acpi_ut_dump_buffer ( display = DB_BYTE_DISPLAY; } - acpi_os_printf ("\nOffset Value\n"); + /* Nasty little dump buffer routine! */ - /* - * Nasty little dump buffer routine! - */ while (i < count) { /* Print current offset */ - acpi_os_printf ("%05X ", (u32) i); + acpi_os_printf ("%6.4X: ", (u32) i); /* Print 16 hex chars */ for (j = 0; j < 16;) { if (i + j >= count) { - acpi_os_printf ("\n"); - return; - } + /* Dump fill spaces */ - /* Make sure that the s8 doesn't get sign-extended! */ + acpi_os_printf ("%*s", ((display * 2) + 1), " "); + j += display; + continue; + } switch (display) { - /* Default is BYTE display */ + default: /* Default is BYTE display */ - default: - - acpi_os_printf ("%02X ", - *((u8 *) &buffer[i + j])); - j += 1; + acpi_os_printf ("%02X ", buffer[i + j]); break; @@ -568,7 +564,6 @@ acpi_ut_dump_buffer ( ACPI_MOVE_16_TO_32 (&temp32, &buffer[i + j]); acpi_os_printf ("%04X ", temp32); - j += 2; break; @@ -576,7 +571,6 @@ acpi_ut_dump_buffer ( ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]); acpi_os_printf ("%08X ", temp32); - j += 4; break; @@ -587,15 +581,17 @@ acpi_ut_dump_buffer ( ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j + 4]); acpi_os_printf ("%08X ", temp32); - j += 8; break; } + + j += display; } /* * Print the ASCII equivalent characters * But watch out for the bad unprintable ones... */ + acpi_os_printf (" "); for (j = 0; j < 16; j++) { if (i + j >= count) { acpi_os_printf ("\n"); diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 9a52ad52a23..bc540302268 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -51,12 +51,23 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utdelete") +/* Local prototypes */ + +static void +acpi_ut_delete_internal_obj ( + union acpi_operand_object *object); + +static void +acpi_ut_update_ref_count ( + union acpi_operand_object *object, + u32 action); + /******************************************************************************* * * FUNCTION: acpi_ut_delete_internal_obj * - * PARAMETERS: *Object - Pointer to the list to be deleted + * PARAMETERS: Object - Object to be deleted * * RETURN: None * @@ -65,7 +76,7 @@ * ******************************************************************************/ -void +static void acpi_ut_delete_internal_obj ( union acpi_operand_object *object) { @@ -152,7 +163,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_MUTEX: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Mutex %p, Semaphore %p\n", object, object->mutex.semaphore)); acpi_ex_unlink_mutex (object); @@ -162,7 +174,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_EVENT: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Event %p, Semaphore %p\n", object, object->event.semaphore)); (void) acpi_os_delete_semaphore (object->event.semaphore); @@ -172,7 +185,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_METHOD: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Method %p\n", object)); /* Delete the method semaphore if it exists */ @@ -185,7 +199,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Region %p\n", object)); second_desc = acpi_ns_get_secondary_object (object); if (second_desc) { @@ -212,7 +227,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_BUFFER_FIELD: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Buffer Field %p\n", object)); second_desc = acpi_ns_get_secondary_object (object); if (second_desc) { @@ -247,7 +263,7 @@ acpi_ut_delete_internal_obj ( * * FUNCTION: acpi_ut_delete_internal_object_list * - * PARAMETERS: *obj_list - Pointer to the list to be deleted + * PARAMETERS: obj_list - Pointer to the list to be deleted * * RETURN: None * @@ -283,7 +299,7 @@ acpi_ut_delete_internal_object_list ( * * FUNCTION: acpi_ut_update_ref_count * - * PARAMETERS: *Object - Object whose ref count is to be updated + * PARAMETERS: Object - Object whose ref count is to be updated * Action - What to do * * RETURN: New ref count @@ -312,7 +328,8 @@ acpi_ut_update_ref_count ( new_count = count; /* - * Perform the reference count action (increment, decrement, or force delete) + * Perform the reference count action + * (increment, decrement, or force delete) */ switch (action) { @@ -321,7 +338,8 @@ acpi_ut_update_ref_count ( new_count++; object->common.reference_count = new_count; - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, [Incremented]\n", object, new_count)); break; @@ -329,7 +347,8 @@ acpi_ut_update_ref_count ( case REF_DECREMENT: if (count < 1) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, can't decrement! (Set to 0)\n", object, new_count)); new_count = 0; @@ -337,12 +356,14 @@ acpi_ut_update_ref_count ( else { new_count--; - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, [Decremented]\n", object, new_count)); } if (ACPI_GET_OBJECT_TYPE (object) == ACPI_TYPE_METHOD) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Method Obj %p Refs=%X, [Decremented]\n", object, new_count)); } @@ -356,7 +377,8 @@ acpi_ut_update_ref_count ( case REF_FORCE_DELETE: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, Force delete! (Set to 0)\n", object, count)); new_count = 0; @@ -390,7 +412,7 @@ acpi_ut_update_ref_count ( * * FUNCTION: acpi_ut_update_object_reference * - * PARAMETERS: *Object - Increment ref count for this object + * PARAMETERS: Object - Increment ref count for this object * and all sub-objects * Action - Either REF_INCREMENT or REF_DECREMENT or * REF_FORCE_DELETE @@ -431,7 +453,8 @@ acpi_ut_update_object_reference ( /* Make sure that this isn't a namespace handle */ if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Object %p is NS handle\n", object)); return_ACPI_STATUS (AE_OK); } @@ -614,8 +637,8 @@ error_exit: * * FUNCTION: acpi_ut_add_reference * - * PARAMETERS: *Object - Object whose reference count is to be - * incremented + * PARAMETERS: Object - Object whose reference count is to be + * incremented * * RETURN: None * @@ -652,7 +675,7 @@ acpi_ut_add_reference ( * * FUNCTION: acpi_ut_remove_reference * - * PARAMETERS: *Object - Object whose ref count will be decremented + * PARAMETERS: Object - Object whose ref count will be decremented * * RETURN: None * diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index ead27d2c4d1..00046dd5d92 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -50,6 +50,19 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("uteval") +/* Local prototypes */ + +static void +acpi_ut_copy_id_string ( + char *destination, + char *source, + acpi_size max_length); + +static acpi_status +acpi_ut_translate_one_cid ( + union acpi_operand_object *obj_desc, + struct acpi_compatible_id *one_cid); + /******************************************************************************* * @@ -237,9 +250,9 @@ acpi_ut_evaluate_object ( * * FUNCTION: acpi_ut_evaluate_numeric_object * - * PARAMETERS: *object_name - Object name to be evaluated + * PARAMETERS: object_name - Object name to be evaluated * device_node - Node for the device - * *Address - Where the value is returned + * Address - Where the value is returned * * RETURN: Status * @@ -303,7 +316,6 @@ acpi_ut_copy_id_string ( acpi_size max_length) { - /* * Workaround for ID strings that have a leading asterisk. This construct * is not allowed by the ACPI specification (ID strings must be @@ -325,7 +337,7 @@ acpi_ut_copy_id_string ( * FUNCTION: acpi_ut_execute_HID * * PARAMETERS: device_node - Node for the device - * *Hid - Where the HID is returned + * Hid - Where the HID is returned * * RETURN: Status * @@ -429,7 +441,7 @@ acpi_ut_translate_one_cid ( * FUNCTION: acpi_ut_execute_CID * * PARAMETERS: device_node - Node for the device - * *Cid - Where the CID is returned + * return_cid_list - Where the CID list is returned * * RETURN: Status * @@ -488,10 +500,10 @@ acpi_ut_execute_CID ( cid_list->size = size; /* - * A _CID can return either a single compatible ID or a package of compatible - * IDs. Each compatible ID can be one of the following: - * -- Number (32 bit compressed EISA ID) or - * -- String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss"). + * A _CID can return either a single compatible ID or a package of + * compatible IDs. Each compatible ID can be one of the following: + * 1) Integer (32 bit compressed EISA ID) or + * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") */ /* The _CID object can be either a single CID or a package (list) of CIDs */ @@ -534,7 +546,7 @@ acpi_ut_execute_CID ( * FUNCTION: acpi_ut_execute_UID * * PARAMETERS: device_node - Node for the device - * *Uid - Where the UID is returned + * Uid - Where the UID is returned * * RETURN: Status * @@ -587,7 +599,7 @@ acpi_ut_execute_UID ( * FUNCTION: acpi_ut_execute_STA * * PARAMETERS: device_node - Node for the device - * *Flags - Where the status flags are returned + * Flags - Where the status flags are returned * * RETURN: Status * @@ -641,7 +653,7 @@ acpi_ut_execute_STA ( * FUNCTION: acpi_ut_execute_Sxds * * PARAMETERS: device_node - Node for the device - * *Flags - Where the status flags are returned + * Flags - Where the status flags are returned * * RETURN: Status * diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 25b0f8ae1bc..4146019b543 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -44,7 +44,6 @@ #define DEFINE_ACPI_GLOBALS #include - #include #include @@ -52,13 +51,14 @@ ACPI_MODULE_NAME ("utglobal") -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_format_exception * * PARAMETERS: Status - The acpi_status code to be formatted * - * RETURN: A string containing the exception text + * RETURN: A string containing the exception text. A valid pointer is + * always returned. * * DESCRIPTION: This function translates an ACPI exception into an ASCII string. * @@ -68,8 +68,8 @@ const char * acpi_format_exception ( acpi_status status) { - const char *exception = "UNKNOWN_STATUS_CODE"; acpi_status sub_status; + const char *exception = NULL; ACPI_FUNCTION_NAME ("format_exception"); @@ -82,57 +82,55 @@ acpi_format_exception ( if (sub_status <= AE_CODE_ENV_MAX) { exception = acpi_gbl_exception_names_env [sub_status]; - break; } - goto unknown; + break; case AE_CODE_PROGRAMMER: if (sub_status <= AE_CODE_PGM_MAX) { exception = acpi_gbl_exception_names_pgm [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_ACPI_TABLES: if (sub_status <= AE_CODE_TBL_MAX) { exception = acpi_gbl_exception_names_tbl [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_AML: if (sub_status <= AE_CODE_AML_MAX) { exception = acpi_gbl_exception_names_aml [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_CONTROL: if (sub_status <= AE_CODE_CTRL_MAX) { exception = acpi_gbl_exception_names_ctrl [sub_status -1]; - break; } - goto unknown; + break; default: - goto unknown; + break; } + if (!exception) { + /* Exception code was not recognized */ - return ((const char *) exception); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown exception code: 0x%8.8X\n", status)); -unknown: + return ((const char *) "UNKNOWN_STATUS_CODE"); + } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status)); return ((const char *) exception); } -/****************************************************************************** +/******************************************************************************* * * Static global variable initialization. * @@ -212,13 +210,12 @@ const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STR }; -/****************************************************************************** +/******************************************************************************* * * Namespace globals * ******************************************************************************/ - /* * Predefined ACPI Names (Built-in to the Interpreter) * @@ -241,9 +238,11 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = #if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) {"_OSI", ACPI_TYPE_METHOD, (char *) 1}, #endif - {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ -}; + /* Table terminator */ + + {NULL, ACPI_TYPE_ANY, NULL} +}; /* * Properties of the ACPI Object Types, both internal and external. @@ -288,22 +287,25 @@ const u8 acpi_gbl_ns_properties[] = /* Hex to ASCII conversion table */ static const char acpi_gbl_hex_to_ascii[] = - {'0','1','2','3','4','5','6','7', - '8','9','A','B','C','D','E','F'}; +{ + '0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F' +}; + -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_hex_to_ascii_char * * PARAMETERS: Integer - Contains the hex digit * Position - bit position of the digit within the - * integer + * integer (multiple of 4) * - * RETURN: Ascii character + * RETURN: The converted Ascii character * - * DESCRIPTION: Convert a hex digit to an ascii character + * DESCRIPTION: Convert a hex digit to an Ascii character * - ****************************************************************************/ + ******************************************************************************/ char acpi_ut_hex_to_ascii_char ( @@ -315,7 +317,7 @@ acpi_ut_hex_to_ascii_char ( } -/****************************************************************************** +/******************************************************************************* * * Table name globals * @@ -324,7 +326,7 @@ acpi_ut_hex_to_ascii_char ( * that are not used by the subsystem are simply ignored. * * Do NOT add any table to this list that is not consumed directly by this - * subsystem. + * subsystem (No MADT, ECDT, SBST, etc.) * ******************************************************************************/ @@ -391,7 +393,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, }; -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_region_name * @@ -401,7 +403,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE * * DESCRIPTION: Translate a Space ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* Region type decoding */ @@ -429,7 +431,6 @@ acpi_ut_get_region_name ( { return ("user_defined_region"); } - else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { return ("invalid_space_id"); @@ -439,7 +440,7 @@ acpi_ut_get_region_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_event_name * @@ -449,7 +450,7 @@ acpi_ut_get_region_name ( * * DESCRIPTION: Translate a Event ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* Event type decoding */ @@ -477,7 +478,7 @@ acpi_ut_get_event_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_type_name * @@ -487,20 +488,21 @@ acpi_ut_get_event_name ( * * DESCRIPTION: Translate a Type ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* * Elements of acpi_gbl_ns_type_names below must match * one-to-one with values of acpi_object_type * - * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when - * stored in a table it really means that we have thus far seen no evidence to - * indicate what type is actually going to be stored for this entry. + * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; + * when stored in a table it really means that we have thus far seen no + * evidence to indicate what type is actually going to be stored for this entry. */ static const char acpi_gbl_bad_type[] = "UNDEFINED"; -#define TYPE_NAME_LENGTH 12 /* Maximum length of each string */ -static const char *acpi_gbl_ns_type_names[] = /* printable names of ACPI types */ +/* Printable names of the ACPI object types */ + +static const char *acpi_gbl_ns_type_names[] = { /* 00 */ "Untyped", /* 01 */ "Integer", @@ -564,7 +566,7 @@ acpi_ut_get_object_type_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_node_name * @@ -574,7 +576,7 @@ acpi_ut_get_object_type_name ( * * DESCRIPTION: Validate the node and return the node's ACPI name. * - ****************************************************************************/ + ******************************************************************************/ char * acpi_ut_get_node_name ( @@ -618,7 +620,7 @@ acpi_ut_get_node_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_descriptor_name * @@ -628,9 +630,11 @@ acpi_ut_get_node_name ( * * DESCRIPTION: Validate object and return the descriptor type * - ****************************************************************************/ + ******************************************************************************/ + +/* Printable names of object descriptor types */ -static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */ +static const char *acpi_gbl_desc_type_names[] = { /* 00 */ "Invalid", /* 01 */ "Cached", @@ -676,17 +680,18 @@ acpi_ut_get_descriptor_name ( * Strings and procedures used for debug only */ -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_mutex_name * - * PARAMETERS: None. + * PARAMETERS: mutex_id - The predefined ID for this mutex. * - * RETURN: Status + * RETURN: String containing the name of the mutex. Always returns a valid + * pointer. * * DESCRIPTION: Translate a mutex ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ char * acpi_ut_get_mutex_name ( @@ -700,21 +705,20 @@ acpi_ut_get_mutex_name ( return (acpi_gbl_mutex_names[mutex_id]); } - #endif -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_valid_object_type * * PARAMETERS: Type - Object type to be validated * - * RETURN: TRUE if valid object type + * RETURN: TRUE if valid object type, FALSE otherwise * * DESCRIPTION: Validate an object type * - ****************************************************************************/ + ******************************************************************************/ u8 acpi_ut_valid_object_type ( @@ -732,7 +736,7 @@ acpi_ut_valid_object_type ( } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_allocate_owner_id * @@ -740,7 +744,10 @@ acpi_ut_valid_object_type ( * * DESCRIPTION: Allocate a table or method owner id * - ***************************************************************************/ + * NOTE: this algorithm has a wraparound problem at 64_k method invocations, and + * should be revisited (TBD) + * + ******************************************************************************/ acpi_owner_id acpi_ut_allocate_owner_id ( @@ -796,16 +803,18 @@ acpi_ut_allocate_owner_id ( } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_init_globals * - * PARAMETERS: none + * PARAMETERS: None + * + * RETURN: None * * DESCRIPTION: Init library globals. All globals that require specific * initialization should be initialized here! * - ***************************************************************************/ + ******************************************************************************/ void acpi_ut_init_globals ( diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index bdbadaf48d2..7f3713889ff 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -49,19 +49,29 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utinit") +/* Local prototypes */ + +static void +acpi_ut_fadt_register_error ( + char *register_name, + u32 value, + acpi_size offset); + +static void acpi_ut_terminate ( + void); + /******************************************************************************* * * FUNCTION: acpi_ut_fadt_register_error * - * PARAMETERS: *register_name - Pointer to string identifying register + * PARAMETERS: register_name - Pointer to string identifying register * Value - Actual register contents value - * acpi_test_spec_section - TDS section containing assertion - * acpi_assertion - Assertion number being tested + * Offset - Byte offset in the FADT * * RETURN: AE_BAD_VALUE * - * DESCRIPTION: Display failure message and link failure to TDS assertion + * DESCRIPTION: Display failure message * ******************************************************************************/ @@ -166,12 +176,13 @@ acpi_ut_validate_fadt ( * * RETURN: none * - * DESCRIPTION: free global memory + * DESCRIPTION: Free global memory * ******************************************************************************/ -void -acpi_ut_terminate (void) +static void +acpi_ut_terminate ( + void) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_block_info *next_gpe_block; @@ -183,8 +194,6 @@ acpi_ut_terminate (void) /* Free global tables, etc. */ - - /* Free global GPE blocks and related info structures */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; @@ -221,7 +230,8 @@ acpi_ut_terminate (void) ******************************************************************************/ void -acpi_ut_subsystem_shutdown (void) +acpi_ut_subsystem_shutdown ( + void) { ACPI_FUNCTION_TRACE ("ut_subsystem_shutdown"); @@ -229,14 +239,16 @@ acpi_ut_subsystem_shutdown (void) /* Just exit if subsystem is already shutdown */ if (acpi_gbl_shutdown) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "ACPI Subsystem is already terminated\n")); return_VOID; } /* Subsystem appears active, go ahead and shut it down */ acpi_gbl_shutdown = TRUE; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Shutting down ACPI Subsystem...\n")); /* Close the acpi_event Handling */ diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 2525c1a9354..0d527c91543 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -259,6 +259,8 @@ acpi_ut_divide ( * * FUNCTION: acpi_ut_short_divide, acpi_ut_divide * + * PARAMETERS: See function headers above + * * DESCRIPTION: Native versions of the ut_divide functions. Use these if either * 1) The target is a 64-bit platform and therefore 64-bit * integer math is supported directly by the machine. diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index f6598547389..f6de4ed3d52 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -49,12 +49,57 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utmisc") +/* Local prototypes */ + +static acpi_status +acpi_ut_create_mutex ( + acpi_mutex_handle mutex_id); + +static acpi_status +acpi_ut_delete_mutex ( + acpi_mutex_handle mutex_id); + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strupr (strupr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: Converted src_string (same as input pointer) + * + * DESCRIPTION: Convert string to uppercase + * + * NOTE: This is not a POSIX function, so it appears here, not in utclib.c + * + ******************************************************************************/ + +char * +acpi_ut_strupr ( + char *src_string) +{ + char *string; + + + ACPI_FUNCTION_ENTRY (); + + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char) ACPI_TOUPPER (*string); + } + + return (src_string); +} + /******************************************************************************* * * FUNCTION: acpi_ut_print_string * * PARAMETERS: String - Null terminated ASCII string + * max_length - Maximum output length * * RETURN: None * @@ -148,6 +193,8 @@ acpi_ut_print_string ( * * PARAMETERS: Value - Value to be converted * + * RETURN: u32 integer with bytes swapped + * * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) * ******************************************************************************/ @@ -160,7 +207,6 @@ acpi_ut_dword_byte_swap ( u32 value; u8 bytes[4]; } out; - union { u32 value; u8 bytes[4]; @@ -219,7 +265,8 @@ acpi_ut_set_integer_width ( * * FUNCTION: acpi_ut_display_init_pathname * - * PARAMETERS: obj_handle - Handle whose pathname will be displayed + * PARAMETERS: Type - Object type of the node + * obj_handle - Handle whose pathname will be displayed * Path - Additional path string to be appended. * (NULL if no extra path) * @@ -270,7 +317,8 @@ acpi_ut_display_init_pathname ( /* Print the object type and pathname */ - acpi_os_printf ("%-12s %s", acpi_ut_get_type_name (type), (char *) buffer.pointer); + acpi_os_printf ("%-12s %s", + acpi_ut_get_type_name (type), (char *) buffer.pointer); /* Extra path is used to append names like _STA, _INI, etc. */ @@ -288,9 +336,9 @@ acpi_ut_display_init_pathname ( * * FUNCTION: acpi_ut_valid_acpi_name * - * PARAMETERS: Character - The character to be examined + * PARAMETERS: Name - The name to be examined * - * RETURN: 1 if Character may appear in a name, else 0 + * RETURN: TRUE if the name is valid, FALSE otherwise * * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: * 1) Upper case alpha @@ -493,40 +541,6 @@ error_exit: } -/******************************************************************************* - * - * FUNCTION: acpi_ut_strupr - * - * PARAMETERS: src_string - The source string to convert to - * - * RETURN: src_string - * - * DESCRIPTION: Convert string to uppercase - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -char * -acpi_ut_strupr ( - char *src_string) -{ - char *string; - - - ACPI_FUNCTION_ENTRY (); - - - /* Walk entire string, uppercasing the letters */ - - for (string = src_string; *string; ) { - *string = (char) ACPI_TOUPPER (*string); - string++; - } - - return (src_string); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ut_mutex_initialize @@ -611,7 +625,7 @@ acpi_ut_mutex_terminate ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_create_mutex ( acpi_mutex_handle mutex_id) { @@ -648,7 +662,7 @@ acpi_ut_create_mutex ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_delete_mutex ( acpi_mutex_handle mutex_id) { @@ -715,16 +729,16 @@ acpi_ut_acquire_mutex ( if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) { if (i == mutex_id) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Mutex [%s] already acquired by this thread [%X]\n", - acpi_ut_get_mutex_name (mutex_id), this_thread_id)); + "Mutex [%s] already acquired by this thread [%X]\n", + acpi_ut_get_mutex_name (mutex_id), this_thread_id)); return (AE_ALREADY_ACQUIRED); } ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid acquire order: Thread %X owns [%s], wants [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (i), - acpi_ut_get_mutex_name (mutex_id))); + "Invalid acquire order: Thread %X owns [%s], wants [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (i), + acpi_ut_get_mutex_name (mutex_id))); return (AE_ACQUIRE_DEADLOCK); } @@ -733,22 +747,23 @@ acpi_ut_acquire_mutex ( #endif ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, - "Thread %X attempting to acquire Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + "Thread %X attempting to acquire Mutex [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); status = acpi_os_wait_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].owner_id = this_thread_id; } else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not acquire Mutex [%s] %s\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id), - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Thread %X could not acquire Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); } return (status); @@ -793,8 +808,8 @@ acpi_ut_release_mutex ( */ if (acpi_gbl_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Mutex [%s] is not acquired, cannot release\n", - acpi_ut_get_mutex_name (mutex_id))); + "Mutex [%s] is not acquired, cannot release\n", + acpi_ut_get_mutex_name (mutex_id))); return (AE_NOT_ACQUIRED); } @@ -812,8 +827,8 @@ acpi_ut_release_mutex ( } ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid release order: owns [%s], releasing [%s]\n", - acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id))); + "Invalid release order: owns [%s], releasing [%s]\n", + acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id))); return (AE_RELEASE_DEADLOCK); } @@ -826,13 +841,14 @@ acpi_ut_release_mutex ( status = acpi_os_signal_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not release Mutex [%s] %s\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id), - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Thread %X could not release Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); } else { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X released Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); } return (status); @@ -843,11 +859,11 @@ acpi_ut_release_mutex ( * * FUNCTION: acpi_ut_create_update_state_and_push * - * PARAMETERS: *Object - Object to be added to the new state + * PARAMETERS: Object - Object to be added to the new state * Action - Increment/Decrement * state_list - List the state will be added to * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Create a new state and push it * @@ -885,15 +901,16 @@ acpi_ut_create_update_state_and_push ( * * FUNCTION: acpi_ut_create_pkg_state_and_push * - * PARAMETERS: *Object - Object to be added to the new state + * PARAMETERS: Object - Object to be added to the new state * Action - Increment/Decrement * state_list - List the state will be added to * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Create a new state and push it * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_ut_create_pkg_state_and_push ( @@ -925,7 +942,7 @@ acpi_ut_create_pkg_state_and_push ( * PARAMETERS: list_head - Head of the state stack * State - State object to push * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Push a state object onto a state stack * @@ -954,7 +971,7 @@ acpi_ut_push_generic_state ( * * PARAMETERS: list_head - Head of the state stack * - * RETURN: Status + * RETURN: The popped state object * * DESCRIPTION: Pop a state object from a state stack * @@ -989,7 +1006,7 @@ acpi_ut_pop_generic_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: The new state object. NULL on failure. * * DESCRIPTION: Create a generic state object. Attempt to obtain one from * the global state cache; If none available, create a new one. @@ -997,7 +1014,8 @@ acpi_ut_pop_generic_state ( ******************************************************************************/ union acpi_generic_state * -acpi_ut_create_generic_state (void) +acpi_ut_create_generic_state ( + void) { union acpi_generic_state *state; @@ -1023,7 +1041,7 @@ acpi_ut_create_generic_state (void) * * PARAMETERS: None * - * RETURN: Thread State + * RETURN: New Thread State. NULL on failure * * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used * to track per-thread info during method execution @@ -1060,11 +1078,10 @@ acpi_ut_create_thread_state ( * * FUNCTION: acpi_ut_create_update_state * - * PARAMETERS: Object - Initial Object to be installed in the - * state - * Action - Update action to be performed + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create an "Update State" - a flavor of the generic state used * to update reference counts and delete complex objects such @@ -1104,11 +1121,10 @@ acpi_ut_create_update_state ( * * FUNCTION: acpi_ut_create_pkg_state * - * PARAMETERS: Object - Initial Object to be installed in the - * state - * Action - Update action to be performed + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create a "Package State" * @@ -1151,7 +1167,7 @@ acpi_ut_create_pkg_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create a "Control State" - a flavor of the generic state used * to support nested IF/WHILE constructs in the AML. @@ -1190,7 +1206,7 @@ acpi_ut_create_control_state ( * * PARAMETERS: State - The state object to be deleted * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Put a state object back into the global state cache. The object * is not actually freed at this time. @@ -1216,7 +1232,7 @@ acpi_ut_delete_generic_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Purge the global state object cache. Used during subsystem * termination. @@ -1240,7 +1256,10 @@ acpi_ut_delete_generic_state_cache ( * * FUNCTION: acpi_ut_walk_package_tree * - * PARAMETERS: obj_desc - The Package object on which to resolve refs + * PARAMETERS: source_object - The package to walk + * target_object - Target object (if package is being copied) + * walk_callback - Called once for each package element + * Context - Passed to the callback function * * RETURN: Status * @@ -1359,7 +1378,7 @@ acpi_ut_walk_package_tree ( * PARAMETERS: Buffer - Buffer to be scanned * Length - number of bytes to examine * - * RETURN: checksum + * RETURN: The generated checksum * * DESCRIPTION: Generate a checksum on a raw buffer * @@ -1442,7 +1461,6 @@ acpi_ut_get_resource_end_tag ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * @@ -1457,7 +1475,6 @@ acpi_ut_report_error ( u32 component_id) { - acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); } @@ -1469,7 +1486,6 @@ acpi_ut_report_error ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * @@ -1495,7 +1511,6 @@ acpi_ut_report_warning ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 9ee40a484e0..cd3899b9cc5 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -50,6 +50,25 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utobject") +/* Local prototypes */ + +static acpi_status +acpi_ut_get_simple_object_size ( + union acpi_operand_object *obj, + acpi_size *obj_length); + +static acpi_status +acpi_ut_get_package_object_size ( + union acpi_operand_object *obj, + acpi_size *obj_length); + +static acpi_status +acpi_ut_get_element_length ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + /******************************************************************************* * @@ -60,7 +79,7 @@ * component_id - Component type of caller * Type - ACPI Type of the new object * - * RETURN: Object - The new object. Null on failure + * RETURN: A new internal object, null on failure * * DESCRIPTION: Create and initialize a new internal object. * @@ -83,7 +102,8 @@ acpi_ut_create_internal_object_dbg ( union acpi_operand_object *second_object; - ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", acpi_ut_get_type_name (type)); + ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", + acpi_ut_get_type_name (type)); /* Allocate the raw object descriptor */ @@ -99,7 +119,8 @@ acpi_ut_create_internal_object_dbg ( /* These types require a secondary object */ - second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); + second_object = acpi_ut_allocate_object_desc_dbg (module_name, + line_number, component_id); if (!second_object) { acpi_ut_delete_object_desc (object); return_PTR (NULL); @@ -138,7 +159,7 @@ acpi_ut_create_internal_object_dbg ( * * PARAMETERS: buffer_size - Size of buffer to be created * - * RETURN: Pointer to a new Buffer object + * RETURN: Pointer to a new Buffer object, null on failure * * DESCRIPTION: Create a fully initialized buffer object * @@ -192,9 +213,9 @@ acpi_ut_create_buffer_object ( * * FUNCTION: acpi_ut_create_string_object * - * PARAMETERS: string_size - Size of string to be created. Does not - * include NULL terminator, this is added - * automatically. + * PARAMETERS: string_size - Size of string to be created. Does not + * include NULL terminator, this is added + * automatically. * * RETURN: Pointer to a new String object * @@ -249,7 +270,9 @@ acpi_ut_create_string_object ( * * PARAMETERS: Object - Object to be validated * - * RETURN: Validate a pointer to be an union acpi_operand_object + * RETURN: TRUE if object is valid, FALSE otherwise + * + * DESCRIPTION: Validate a pointer to be an union acpi_operand_object * ******************************************************************************/ @@ -399,8 +422,8 @@ acpi_ut_delete_object_cache ( * * FUNCTION: acpi_ut_get_simple_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length is returned + * PARAMETERS: internal_object - An ACPI operand object + * obj_length - Where the length is returned * * RETURN: Status * @@ -412,7 +435,7 @@ acpi_ut_delete_object_cache ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_simple_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) @@ -424,8 +447,10 @@ acpi_ut_get_simple_object_size ( ACPI_FUNCTION_TRACE_PTR ("ut_get_simple_object_size", internal_object); - /* Handle a null object (Could be a uninitialized package element -- which is legal) */ - + /* + * Handle a null object (Could be a uninitialized package + * element -- which is legal) + */ if (!internal_object) { *obj_length = 0; return_ACPI_STATUS (AE_OK); @@ -480,7 +505,8 @@ acpi_ut_get_simple_object_size ( * Get the actual length of the full pathname to this object. * The reference will be converted to the pathname to the object */ - length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); + length += ACPI_ROUND_UP_TO_NATIVE_WORD ( + acpi_ns_get_pathname_length (internal_object->reference.node)); break; default: @@ -530,7 +556,7 @@ acpi_ut_get_simple_object_size ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_element_length ( u8 object_type, union acpi_operand_object *source_object, @@ -582,8 +608,8 @@ acpi_ut_get_element_length ( * * FUNCTION: acpi_ut_get_package_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length is returned + * PARAMETERS: internal_object - An ACPI internal object + * obj_length - Where the length is returned * * RETURN: Status * @@ -595,7 +621,7 @@ acpi_ut_get_element_length ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_package_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) @@ -636,8 +662,8 @@ acpi_ut_get_package_object_size ( * * FUNCTION: acpi_ut_get_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length will be returned + * PARAMETERS: internal_object - An ACPI internal object + * obj_length - Where the length will be returned * * RETURN: Status * @@ -647,7 +673,7 @@ acpi_ut_get_package_object_size ( ******************************************************************************/ acpi_status -acpi_ut_get_object_size( +acpi_ut_get_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) { diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 97a91f3f06f..e8803d81065 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -73,6 +73,7 @@ acpi_initialize_subsystem ( { acpi_status status; + ACPI_FUNCTION_TRACE ("acpi_initialize_subsystem"); @@ -105,7 +106,6 @@ acpi_initialize_subsystem ( * Initialize the namespace manager and * the root of the namespace tree */ - status = acpi_ns_root_initialize (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n", @@ -113,7 +113,6 @@ acpi_initialize_subsystem ( return_ACPI_STATUS (status); } - /* If configured, initialize the AML debugger */ ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ()); @@ -150,7 +149,8 @@ acpi_enable_subsystem ( * The values from the FADT are validated here. */ if (!(flags & ACPI_NO_HARDWARE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI hardware\n")); status = acpi_hw_initialize (); if (ACPI_FAILURE (status)) { @@ -178,7 +178,8 @@ acpi_enable_subsystem ( * install_address_space_handler interface. */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Installing default address space handlers\n")); status = acpi_ev_install_region_handlers (); if (ACPI_FAILURE (status)) { @@ -189,12 +190,14 @@ acpi_enable_subsystem ( /* * Initialize ACPI Event handling (Fixed and General Purpose) * - * NOTE: We must have the hardware AND events initialized before we can execute - * ANY control methods SAFELY. Any control method can require ACPI hardware - * support, so the hardware MUST be initialized before execution! + * NOTE: We must have the hardware AND events initialized before we can + * execute ANY control methods SAFELY. Any control method can require + * ACPI hardware support, so the hardware MUST be initialized before + * execution! */ if (!(flags & ACPI_NO_EVENT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI events\n")); status = acpi_ev_initialize_events (); if (ACPI_FAILURE (status)) { @@ -205,7 +208,8 @@ acpi_enable_subsystem ( /* Install the SCI handler and Global Lock handler */ if (!(flags & ACPI_NO_HANDLER_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Installing SCI/GL handlers\n")); status = acpi_ev_install_xrupt_handlers (); if (ACPI_FAILURE (status)) { @@ -247,7 +251,8 @@ acpi_initialize_objects ( * contain executable AML (see call to acpi_ns_initialize_objects below). */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Executing _REG op_region methods\n")); status = acpi_ev_initialize_op_regions (); if (ACPI_FAILURE (status)) { @@ -261,7 +266,8 @@ acpi_initialize_objects ( * objects: operation_regions, buffer_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Completing Initialization of ACPI Objects\n")); status = acpi_ns_initialize_objects (); if (ACPI_FAILURE (status)) { @@ -274,7 +280,8 @@ acpi_initialize_objects ( * This runs the _STA and _INI methods. */ if (!(flags & ACPI_NO_DEVICE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI Devices\n")); status = acpi_ns_initialize_devices (); if (ACPI_FAILURE (status)) { @@ -307,7 +314,8 @@ acpi_initialize_objects ( ******************************************************************************/ acpi_status -acpi_terminate (void) +acpi_terminate ( + void) { acpi_status status; @@ -344,8 +352,7 @@ acpi_terminate (void) #ifdef ACPI_FUTURE_USAGE - -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_subsystem_status * @@ -354,14 +361,16 @@ acpi_terminate (void) * RETURN: Status of the ACPI subsystem * * DESCRIPTION: Other drivers that use the ACPI subsystem should call this - * before making any other calls, to ensure the subsystem initial- - * ized successfully. + * before making any other calls, to ensure the subsystem + * initialized successfully. * - ****************************************************************************/ + ******************************************************************************/ acpi_status -acpi_subsystem_status (void) +acpi_subsystem_status ( + void) { + if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) { return (AE_OK); } @@ -371,13 +380,12 @@ acpi_subsystem_status (void) } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_get_system_info * - * PARAMETERS: out_buffer - a pointer to a buffer to receive the - * resources for the device - * buffer_length - the number of bytes available in the buffer + * PARAMETERS: out_buffer - A buffer to receive the resources for the + * device * * RETURN: Status - the status of the call * @@ -395,8 +403,8 @@ acpi_get_system_info ( struct acpi_buffer *out_buffer) { struct acpi_system_info *info_ptr; - u32 i; acpi_status status; + u32 i; ACPI_FUNCTION_TRACE ("acpi_get_system_info"); @@ -466,6 +474,7 @@ EXPORT_SYMBOL(acpi_get_system_info); * FUNCTION: acpi_install_initialization_handler * * PARAMETERS: Handler - Callback procedure + * Function - Not (currently) used, see below * * RETURN: Status * @@ -495,7 +504,6 @@ acpi_install_initialization_handler ( #endif /* ACPI_FUTURE_USAGE */ - /***************************************************************************** * * FUNCTION: acpi_purge_cached_objects @@ -509,7 +517,8 @@ acpi_install_initialization_handler ( ****************************************************************************/ acpi_status -acpi_purge_cached_objects (void) +acpi_purge_cached_objects ( + void) { ACPI_FUNCTION_TRACE ("acpi_purge_cached_objects"); -- cgit v1.2.3 From ef7b06cd905424aea7c31f27fef622e84e75e650 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Mon, 18 Apr 2005 22:59:23 -0400 Subject: [ACPI] quiet dmesg related to ACPI PM of PCI devices DBG("No ACPI bus support for %s\n", dev->bus_id); http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/glue.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index b6d2045caf3..770cfc8b17e 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -29,7 +29,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type) down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); - DBG("ACPI bus type %s registered\n", type->bus->name); + printk(KERN_INFO PREFIX "bus type %s registered\n", type->bus->name); return 0; } return -ENODEV; @@ -45,7 +45,7 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type) down_write(&bus_type_sem); list_del_init(&type->list); up_write(&bus_type_sem); - DBG("ACPI bus type %s unregistered\n", type->bus->name); + printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", type->bus->name); return 0; } return -ENODEV; @@ -314,14 +314,12 @@ static int acpi_platform_notify(struct device *dev) } type = acpi_get_bus_type(dev->bus); if (!type) { - printk(KERN_INFO PREFIX "No ACPI bus support for %s\n", - dev->bus_id); + DBG("No ACPI bus support for %s\n", dev->bus_id); ret = -EINVAL; goto end; } if ((ret = type->find_device(dev, &handle)) != 0) - printk(KERN_INFO PREFIX "Can't get handler for %s\n", - dev->bus_id); + DBG("Can't get handler for %s\n", dev->bus_id); end: if (!ret) acpi_bind_one(dev, handle); -- cgit v1.2.3 From 590275ce72c48fdbddea057bc9ee379c1fd851ef Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 18 Apr 2005 23:52:17 -0400 Subject: [ACPI] cleanup: delete !IA64_SGI_SN from acpi/Kconfig Signed-off-by: Jesse Barnes Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8b6de146255..84bbcb051cb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -49,7 +49,6 @@ config ACPI_BOOT config ACPI_INTERPRETER bool - depends on !IA64_SGI_SN default y if ACPI_INTERPRETER @@ -108,7 +107,6 @@ config ACPI_BATTERY config ACPI_BUTTON tristate "Button" - depends on !IA64_SGI_SN default m help This driver registers for events based on buttons, such as the @@ -120,7 +118,6 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on EXPERIMENTAL - depends on !IA64_SGI_SN default m help This driver implement the ACPI Extensions For Display Adapters @@ -142,7 +139,6 @@ config ACPI_HOTKEY config ACPI_FAN tristate "Fan" - depends on !IA64_SGI_SN default m help This driver adds support for ACPI fan devices, allowing user-mode @@ -150,7 +146,6 @@ config ACPI_FAN config ACPI_PROCESSOR tristate "Processor" - depends on !IA64_SGI_SN default m help This driver installs ACPI as the idle handler for Linux, and uses @@ -160,7 +155,6 @@ config ACPI_PROCESSOR config ACPI_HOTPLUG_CPU bool "Processor Hotplug (EXPERIMENTAL)" depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL - depends on !IA64_SGI_SN select ACPI_CONTAINER default n ---help--- @@ -280,7 +274,6 @@ config ACPI_BLACKLIST_YEAR config ACPI_DEBUG bool "Debug Statements" - depends on !IA64_SGI_SN default n help The ACPI driver can optionally report errors with a great deal @@ -289,7 +282,6 @@ config ACPI_DEBUG config ACPI_BUS bool - depends on !IA64_SGI_SN default y config ACPI_EC @@ -303,17 +295,14 @@ config ACPI_EC config ACPI_POWER bool - depends on !IA64_SGI_SN default y config ACPI_PCI bool - depends on !IA64_SGI_SN default PCI config ACPI_SYSTEM bool - depends on !IA64_SGI_SN default y help This driver will enable your system to shut down using ACPI, and -- cgit v1.2.3 From a27ac38efd6dc6dccebfc9bcc475ab4aa5fc4a56 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 5 Apr 2019 00:07:45 -0500 Subject: [ACPI] fix merge error that broke CONFIG_ACPI_DEBUG=y build Signed-off-by: Len Brown --- drivers/acpi/namespace/nsdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 4550e6f9809..6c2aef0e0dd 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -612,6 +612,7 @@ acpi_ns_dump_objects ( ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, (void *) &info, NULL); } +#endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -694,5 +695,4 @@ acpi_ns_dump_tables ( return_VOID; } #endif /* _ACPI_ASL_COMPILER */ -#endif /* ACPI_FUTURE_USAGE */ #endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */ -- cgit v1.2.3 From 17e9c78a75ce9eacd61200f9e1f1924012e28846 Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Fri, 22 Apr 2005 23:07:10 -0400 Subject: [ACPI] EC GPE-disabled issue http://bugzilla.kernel.org/show_bug.cgi?id=3851 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a4b70dfdcf0..8e665f2e313 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -282,7 +282,7 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ + while(atomic_read(&ec->pending_gpe)){ msleep(1); } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); @@ -365,7 +365,7 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ + while(atomic_read(&ec->pending_gpe)){ msleep(1); } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); @@ -431,7 +431,6 @@ acpi_ec_query ( if (!ec || !data) return_VALUE(-EINVAL); -retry: *data = 0; if (ec->global_lock) { @@ -469,13 +468,9 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ - msleep(1); - } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); - goto retry; + status = -ENODATA; } - return_VALUE(status); } @@ -514,8 +509,8 @@ acpi_ec_gpe_query ( ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - atomic_dec(&ec->pending_gpe); end: + atomic_dec(&ec->pending_gpe); return; } @@ -553,7 +548,7 @@ acpi_ec_gpe_handler ( !(value & ACPI_EC_FLAG_IBF))) { ec->expect_event = 0; wake_up(&ec->wait); - + return ACPI_INTERRUPT_HANDLED; } } @@ -561,8 +556,10 @@ acpi_ec_gpe_handler ( atomic_add(1, &ec->pending_gpe) ; status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); + return status == AE_OK ? + ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } - + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -688,6 +685,7 @@ acpi_ec_read_info (struct seq_file *seq, void *offset) (u32) ec->status_addr.address, (u32) ec->data_addr.address); seq_printf(seq, "use global lock: %s\n", ec->global_lock?"yes":"no"); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); end: return_VALUE(0); -- cgit v1.2.3 From 6a2e9b738cb5c929df73b6acabdd8f9a4e9a0416 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 11 Jul 2005 21:13:56 -0700 Subject: [NET]: move config options out to individual protocols Move the protocol specific config options out to the specific protocols. With this change net/Kconfig now starts to become readable and serve as a good basis for further re-structuring. The menu structure is left almost intact, except that indention is fixed in most cases. Most visible are the INET changes where several "depends on INET" are replaced with a single ifdef INET / endif pair. Several new files were created to accomplish this change - they are small but serve the purpose that config options are now distributed out where they belongs. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/net/appletalk/Kconfig | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index 69c488d933a..b14e89004c3 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -1,6 +1,33 @@ # # Appletalk driver configuration # +config ATALK + tristate "Appletalk protocol support" + select LLC + ---help--- + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network and you + wish to connect to it, say Y. You will need to use the netatalk package + so that your Linux box can act as a print and file server for Macs as + well as access AppleTalk printers. Check out + on the WWW for details. + EtherTalk is the name used for AppleTalk over Ethernet and the + cheaper and slower LocalTalk is AppleTalk over a proprietary Apple + network using serial links. EtherTalk and LocalTalk are fully + supported by Linux. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at . The + NET-3-HOWTO, available from + , contains valuable + information as well. + + To compile this driver as a module, choose M here: the module will be + called appletalk. You almost certainly want to compile it as a + module so you can restart your AppleTalk stack without rebooting + your machine. I hear that the GNU boycott of Apple is over, so + even politically correct people are allowed to say Y here. + config DEV_APPLETALK bool "Appletalk interfaces support" depends on ATALK -- cgit v1.2.3 From 02df8b9385c21fdba165bd380f60eca1d3b0578b Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Fri, 15 Apr 2005 15:07:10 -0400 Subject: [ACPI] enable C2 and C3 idle power states on SMP http://bugzilla.kernel.org/show_bug.cgi?id=4401 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 37 ++++++++++++++ drivers/acpi/processor_idle.c | 105 ++++++++++++++++++++++++++------------- drivers/acpi/processor_perflib.c | 33 +----------- 3 files changed, 109 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f4778747e88..e421842888b 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -255,6 +255,43 @@ acpi_processor_errata ( } +/* -------------------------------------------------------------------------- + Common ACPI processor fucntions + -------------------------------------------------------------------------- */ + +/* + * _PDC is required for a BIOS-OS handshake for most of the newer + * ACPI processor features. + */ + +int acpi_processor_set_pdc(struct acpi_processor *pr, + struct acpi_object_list *pdc_in) +{ + acpi_status status = AE_OK; + u32 arg0_buf[3]; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + struct acpi_object_list no_object = {1, &arg0}; + struct acpi_object_list *pdc; + + ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); + + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; + arg0_buf[0] = ACPI_PDC_REVISION_ID; + arg0_buf[1] = 0; + arg0_buf[2] = 0; + + pdc = (pdc_in) ? pdc_in : &no_object; + + status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); + + if ((ACPI_FAILURE(status)) && (pdc_in)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); + + return_VALUE(status); +} + + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 79d5ca3066c..8f038cd2947 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -6,6 +6,8 @@ * Copyright (C) 2004 Dominik Brodowski * Copyright (C) 2004 Anil S Keshavamurthy * - Added processor hotplug support + * Copyright (C) 2005 Venkatesh Pallipadi + * - Added support for C3 on SMP * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -142,7 +144,7 @@ acpi_processor_power_activate ( switch (old->type) { case ACPI_STATE_C3: /* Disable bus master reload */ - if (new->type != ACPI_STATE_C3) + if (new->type != ACPI_STATE_C3 && pr->flags.bm_check) acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK); break; } @@ -152,7 +154,7 @@ acpi_processor_power_activate ( switch (new->type) { case ACPI_STATE_C3: /* Enable bus master reload */ - if (old->type != ACPI_STATE_C3) + if (old->type != ACPI_STATE_C3 && pr->flags.bm_check) acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK); break; } @@ -163,6 +165,9 @@ acpi_processor_power_activate ( } +static atomic_t c3_cpu_count; + + static void acpi_processor_idle (void) { struct acpi_processor *pr = NULL; @@ -297,8 +302,22 @@ static void acpi_processor_idle (void) break; case ACPI_STATE_C3: - /* Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); + + if (pr->flags.bm_check) { + if (atomic_inc_return(&c3_cpu_count) == + num_online_cpus()) { + /* + * All CPUs are trying to go to C3 + * Disable bus master arbitration + */ + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, + ACPI_MTX_DO_NOT_LOCK); + } + } else { + /* SMP with no shared cache... Invalidate cache */ + ACPI_FLUSH_CPU_CACHE(); + } + /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C3 */ @@ -307,8 +326,12 @@ static void acpi_processor_idle (void) t2 = inl(acpi_fadt.xpm_tmr_blk.address); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); - /* Enable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); + if (pr->flags.bm_check) { + /* Enable bus master arbitration */ + atomic_dec(&c3_cpu_count); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); + } + /* Re-enable interrupts */ local_irq_enable(); /* Compute time (ticks) that we were actually asleep */ @@ -552,9 +575,6 @@ static int acpi_processor_get_power_info_cst (struct acpi_processor *pr) ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst"); - if (errata.smp) - return_VALUE(-ENODEV); - if (nocst) return_VALUE(-ENODEV); @@ -687,13 +707,6 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) return_VOID; } - /* We're (currently) only supporting C2 on UP */ - else if (errata.smp) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C2 not supported in SMP mode\n")); - return_VOID; - } - /* * Otherwise we've met all of our C2 requirements. * Normalize the C2 latency to expidite policy @@ -709,6 +722,8 @@ static void acpi_processor_power_verify_c3( struct acpi_processor *pr, struct acpi_processor_cx *cx) { + static int bm_check_flag; + ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3"); if (!cx->address) @@ -725,20 +740,6 @@ static void acpi_processor_power_verify_c3( return_VOID; } - /* bus mastering control is necessary */ - else if (!pr->flags.bm_control) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 support requires bus mastering control\n")); - return_VOID; - } - - /* We're (currently) only supporting C2 on UP */ - else if (errata.smp) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 not supported in SMP mode\n")); - return_VOID; - } - /* * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) * DMA transfers are used by any ISA device to avoid livelock. @@ -752,6 +753,39 @@ static void acpi_processor_power_verify_c3( return_VOID; } + /* All the logic here assumes flags.bm_check is same across all CPUs */ + if (!bm_check_flag) { + /* Determine whether bm_check is needed based on CPU */ + acpi_processor_power_init_bm_check(&(pr->flags), pr->id); + bm_check_flag = pr->flags.bm_check; + } else { + pr->flags.bm_check = bm_check_flag; + } + + if (pr->flags.bm_check) { + printk("Disabling BM access before entering C3\n"); + /* bus mastering control is necessary */ + if (!pr->flags.bm_control) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 support requires bus mastering control\n")); + return_VOID; + } + } else { + printk("Invalidating cache before entering C3\n"); + /* + * WBINVD should be set in fadt, for C3 state to be + * supported on when bm_check is not required. + */ + if (acpi_fadt.wb_invd != 1) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Cache invalidation should work properly" + " for C3 to be enabled on SMP systems\n")); + return_VOID; + } + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, + 0, ACPI_MTX_DO_NOT_LOCK); + } + /* * Otherwise we've met all of our C3 requirements. * Normalize the C3 latency to expidite policy. Enable @@ -760,7 +794,6 @@ static void acpi_processor_power_verify_c3( */ cx->valid = 1; cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); - pr->flags.bm_check = 1; return_VOID; } @@ -848,7 +881,7 @@ int acpi_processor_cst_has_changed (struct acpi_processor *pr) if (!pr) return_VALUE(-EINVAL); - if (errata.smp || nocst) { + if ( nocst) { return_VALUE(-ENODEV); } @@ -948,7 +981,6 @@ static struct file_operations acpi_processor_power_fops = { .release = single_release, }; - int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; @@ -965,7 +997,10 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev first_run++; } - if (!errata.smp && (pr->id == 0) && acpi_fadt.cst_cnt && !nocst) { + if (!pr) + return_VALUE(-EINVAL); + + if (acpi_fadt.cst_cnt && !nocst) { status = acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -973,6 +1008,8 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev } } + acpi_processor_power_init_pdc(&(pr->power), pr->id); + acpi_processor_set_pdc(pr, pr->power.pdc); acpi_processor_get_power_info(pr); /* diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index a9a1a8fe319..1f0d6256302 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -165,37 +165,6 @@ void acpi_processor_ppc_exit(void) { acpi_processor_ppc_status &= ~PPC_REGISTERED; } -/* - * when registering a cpufreq driver with this ACPI processor driver, the - * _PCT and _PSS structures are read out and written into struct - * acpi_processor_performance. - */ -static int acpi_processor_set_pdc (struct acpi_processor *pr) -{ - acpi_status status = AE_OK; - u32 arg0_buf[3]; - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - struct acpi_object_list no_object = {1, &arg0}; - struct acpi_object_list *pdc; - - ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); - - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; - arg0_buf[0] = ACPI_PDC_REVISION_ID; - arg0_buf[1] = 0; - arg0_buf[2] = 0; - - pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object; - - status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); - - if ((ACPI_FAILURE(status)) && (pr->performance->pdc)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); - - return_VALUE(status); -} - static int acpi_processor_get_performance_control ( @@ -357,7 +326,7 @@ acpi_processor_get_performance_info ( if (!pr || !pr->performance || !pr->handle) return_VALUE(-EINVAL); - acpi_processor_set_pdc(pr); + acpi_processor_set_pdc(pr, pr->performance->pdc); status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { -- cgit v1.2.3 From cf5910bbae81b95bdf120e01fd365ad7b939b143 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: add bMaxPacketSize0 attribute to sysfs For some reason this was not there... Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 740cb4c668d..00297f11384 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -196,6 +196,7 @@ usb_descriptor_attr (bDeviceClass, "%02x\n") usb_descriptor_attr (bDeviceSubClass, "%02x\n") usb_descriptor_attr (bDeviceProtocol, "%02x\n") usb_descriptor_attr (bNumConfigurations, "%d\n") +usb_descriptor_attr (bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -211,6 +212,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bDeviceSubClass.attr, &dev_attr_bDeviceProtocol.attr, &dev_attr_bNumConfigurations.attr, + &dev_attr_bMaxPacketSize0.attr, &dev_attr_speed.attr, &dev_attr_devnum.attr, &dev_attr_version.attr, -- cgit v1.2.3 From e8116e84b56f8fa4f091b967a045f47c55095c68 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Wed, 22 Jun 2005 22:47:13 -0700 Subject: [PATCH] USB Storage: Remove unneeded SC/P This patch removes an unneeded subclass and protocol from the 07af/0005/100 entry in unsual_devs.h as reported by Alfred Ganz . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 9fcc7bd1fbe..bd0ab3039bd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -697,7 +697,7 @@ UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, "Microtech", "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), #ifdef CONFIG_USB_STORAGE_DPCM -- cgit v1.2.3 From 9c8d61783e5bb5e29744b6481a1c67c6e4e8e135 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 20 Jun 2005 14:29:58 -0700 Subject: [PATCH] USB: khubd: use kthread API Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 32ff3218185..c3e46d24a37 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,7 @@ static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ /* Wakes up khubd */ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); -static pid_t khubd_pid = 0; /* PID of khubd */ -static DECLARE_COMPLETION(khubd_exited); +static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; @@ -2807,23 +2807,16 @@ loop: static int hub_thread(void *__unused) { - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources - */ - - daemonize("khubd"); - allow_signal(SIGKILL); - - /* Send me a signal to get me die (for debugging) */ do { hub_events(); - wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); + wait_event_interruptible(khubd_wait, + !list_empty(&hub_event_list) || + kthread_should_stop()); try_to_freeze(); - } while (!signal_pending(current)); + } while (!kthread_should_stop() || !list_empty(&hub_event_list)); - pr_debug ("%s: khubd exiting\n", usbcore_name); - complete_and_exit(&khubd_exited, 0); + pr_debug("%s: khubd exiting\n", usbcore_name); + return 0; } static struct usb_device_id hub_id_table [] = { @@ -2849,20 +2842,15 @@ static struct usb_driver hub_driver = { int usb_hub_init(void) { - pid_t pid; - if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n", usbcore_name); return -1; } - pid = kernel_thread(hub_thread, NULL, CLONE_KERNEL); - if (pid >= 0) { - khubd_pid = pid; - + khubd_task = kthread_run(hub_thread, NULL, "khubd"); + if (!IS_ERR(khubd_task)) return 0; - } /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); @@ -2873,12 +2861,7 @@ int usb_hub_init(void) void usb_hub_cleanup(void) { - int ret; - - /* Kill the thread */ - ret = kill_proc(khubd_pid, SIGKILL, 1); - - wait_for_completion(&khubd_exited); + kthread_stop(khubd_task); /* * Hub resources are freed for us by usb_deregister. It calls @@ -2890,7 +2873,6 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ - static int config_descriptors_changed(struct usb_device *udev) { unsigned index; -- cgit v1.2.3 From 8f977e4201fcc0bd512eb01e775894e0a9c34a39 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 16:45:42 +0100 Subject: [PATCH] USB ftdi_sio: reduce device id table clutter ftdi_sio: Use a single usb_device_id table and detect the type of chip programatically. The table also flags devices requiring special initialization. The patch makes the driver about 10K smaller and makes it easier to add new device IDs. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 707 +++++++++--------------------------------- 1 file changed, 144 insertions(+), 563 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d882fa3ad19..f843f735886 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -264,16 +264,26 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.2" +#define DRIVER_VERSION "v1.4.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" static int debug; -static struct usb_device_id id_table_sio [] = { - { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, - { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { } /* Terminating entry */ +/* struct ftdi_sio_quirk is used by devices requiring special attention. */ +struct ftdi_sio_quirk { + void (*setup)(struct usb_serial *); /* Special settings during startup. */ +}; + +static void ftdi_USB_UIRT_setup (struct usb_serial *serial); +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial); + +static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { + .setup = ftdi_USB_UIRT_setup, +}; + +static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { + .setup = ftdi_HE_TIRA1_setup, }; /* @@ -288,237 +298,11 @@ static struct usb_device_id id_table_sio [] = { * the bcdDevice value is used to differentiate FT232BM and FT245BM from * the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID * combinations in both tables. - * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know - * if those ever went into mass production. [Ian Abbott] + * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices, + * but I don't know if those ever went into mass production. [Ian Abbott] */ -static struct usb_device_id id_table_8U232AM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, - { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT232BM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_USB_UIRT [] = { - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_HE_TIRA1 [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT2232C[] = { - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, - { } /* Terminating entry */ -}; - static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, @@ -540,14 +324,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, @@ -597,35 +381,37 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), + .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), + .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, @@ -642,7 +428,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { } /* Terminating entry */ }; @@ -705,12 +491,8 @@ struct ftdi_private { ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP ) /* function prototypes for a FTDI serial converter */ -static int ftdi_SIO_startup (struct usb_serial *serial); -static int ftdi_8U232AM_startup (struct usb_serial *serial); -static int ftdi_FT232BM_startup (struct usb_serial *serial); -static int ftdi_FT2232C_startup (struct usb_serial *serial); -static int ftdi_USB_UIRT_startup (struct usb_serial *serial); -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id); +static int ftdi_sio_attach (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); static int ftdi_open (struct usb_serial_port *port, struct file *filp); static void ftdi_close (struct usb_serial_port *port, struct file *filp); @@ -733,66 +515,16 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud); static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); -static struct usb_serial_device_type ftdi_SIO_device = { - .owner = THIS_MODULE, - .name = "FTDI SIO", - .id_table = id_table_sio, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_SIO_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_8U232AM_device = { - .owner = THIS_MODULE, - .name = "FTDI 8U232AM Compatible", - .id_table = id_table_8U232AM, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_8U232AM_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_FT232BM_device = { +static struct usb_serial_device_type ftdi_sio_device = { .owner = THIS_MODULE, - .name = "FTDI FT232BM Compatible", - .id_table = id_table_FT232BM, + .name = "FTDI USB Serial Device", + .short_name = "ftdi_sio", + .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, + .probe = ftdi_sio_probe, .open = ftdi_open, .close = ftdi_close, .throttle = ftdi_throttle, @@ -807,91 +539,10 @@ static struct usb_serial_device_type ftdi_FT232BM_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT232BM_startup, + .attach = ftdi_sio_attach, .shutdown = ftdi_shutdown, }; -static struct usb_serial_device_type ftdi_FT2232C_device = { - .owner = THIS_MODULE, - .name = "FTDI FT2232C Compatible", - .id_table = id_table_FT2232C, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT2232C_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_USB_UIRT_device = { - .owner = THIS_MODULE, - .name = "USB-UIRT Infrared Tranceiver", - .id_table = id_table_USB_UIRT, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_USB_UIRT_startup, - .shutdown = ftdi_shutdown, -}; - -/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000 - * and which requires RTS-CTS to be enabled. */ -static struct usb_serial_device_type ftdi_HE_TIRA1_device = { - .owner = THIS_MODULE, - .name = "Home-Electronics TIRA-1 IR Transceiver", - .id_table = id_table_HE_TIRA1, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_HE_TIRA1_startup, - .shutdown = ftdi_shutdown, -}; - - #define WDR_TIMEOUT 5000 /* default urb timeout */ @@ -1212,6 +863,59 @@ check_and_exit: } /* set_serial_info */ +/* Determine type of FTDI chip based on USB config and descriptor. */ +static void ftdi_determine_type(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + struct usb_device *udev = serial->dev; + unsigned version; + unsigned interfaces; + + /* Assume it is not the original SIO device for now. */ + priv->baud_base = 48000000 / 16; + priv->write_offset = 0; + + version = le16_to_cpu(udev->descriptor.bcdDevice); + interfaces = udev->actconfig->desc.bNumInterfaces; + dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__, + version, interfaces); + if (interfaces > 1) { + int inter; + + /* Multiple interfaces. Assume FT2232C. */ + priv->chip_type = FT2232C; + /* Determine interface code. */ + inter = serial->interface->altsetting->desc.bInterfaceNumber; + if (inter == 0) { + priv->interface = PIT_SIOA; + } else { + priv->interface = PIT_SIOB; + } + /* BM-type devices have a bug where bcdDevice gets set + * to 0x200 when iSerialNumber is 0. */ + if (version < 0x500) { + dbg("%s: something fishy - bcdDevice too low for multi-interface device", + __FUNCTION__); + } + } else if (version < 0x200) { + /* Old device. Assume its the original SIO. */ + priv->chip_type = SIO; + priv->baud_base = 12000000 / 16; + priv->write_offset = 1; + } else if (version < 0x400) { + /* Assume its an FT8U232AM (or FT8U245AM) */ + /* (It might be a BM because of the iSerialNumber bug, + * but it will still work as an AM device.) */ + priv->chip_type = FT8U232AM; + } else { + /* Assume its an FT232BM (or FT245BM) */ + priv->chip_type = FT232BM; + } + info("Detected %s", ftdi_chip_name[priv->chip_type]); +} + + /* * *************************************************************************** * Sysfs Attribute @@ -1355,12 +1059,20 @@ static void remove_sysfs_attrs(struct usb_serial *serial) * *************************************************************************** */ -/* Common startup subroutine */ -/* Called from ftdi_SIO_startup, etc. */ -static int ftdi_common_startup (struct usb_serial *serial) +/* Probe function to check for special devices */ +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id->driver_info); + + return (0); +} + +/* attach subroutine */ +static int ftdi_sio_attach (struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv; + struct ftdi_sio_quirk *quirk; dbg("%s",__FUNCTION__); @@ -1400,150 +1112,49 @@ static int ftdi_common_startup (struct usb_serial *serial) port->bulk_out_buffer = NULL; usb_set_serial_port_data(serial->port[0], priv); - - return (0); -} - - -/* Startup for the SIO chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_SIO_startup (struct usb_serial *serial) -{ - struct ftdi_private *priv; - int err; - dbg("%s",__FUNCTION__); - - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - priv->write_offset = 1; - - return (0); -} - -/* Startup for the 8U232AM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_8U232AM_startup (struct usb_serial *serial) -{ /* ftdi_8U232AM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT8U232AM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */ - + ftdi_determine_type (serial->port[0]); create_sysfs_attrs(serial); - - return (0); -} /* ftdi_8U232AM_startup */ -/* Startup for the FT232BM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT232BM_startup (struct usb_serial *serial) -{ /* ftdi_FT232BM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); + /* Check for device requiring special set up. */ + quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial); + if (quirk && quirk->setup) { + quirk->setup(serial); } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT232BM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */ - create_sysfs_attrs(serial); - return (0); -} /* ftdi_FT232BM_startup */ +} /* ftdi_sio_attach */ -/* Startup for the FT2232C chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT2232C_startup (struct usb_serial *serial) -{ /* ftdi_FT2232C_startup */ - struct ftdi_private *priv; - int err; - int inter; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT2232C; - inter = serial->interface->altsetting->desc.bInterfaceNumber; - - if (inter) { - priv->interface = PIT_SIOB; - } - else { - priv->interface = PIT_SIOA; - } - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ - - create_sysfs_attrs(serial); - - return (0); -} /* ftdi_FT2232C_startup */ -/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ +/* Setup for the USB-UIRT device, which requires hardwired + * baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ -static int ftdi_USB_UIRT_startup (struct usb_serial *serial) -{ /* ftdi_USB_UIRT_startup */ +static void ftdi_USB_UIRT_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_8U232AM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = B38400; - - return (0); -} /* ftdi_USB_UIRT_startup */ +} /* ftdi_USB_UIRT_setup */ -/* Startup for the HE-TIRA1 device, which requires hardwired - * baudrate (38400 gets mapped to 100000) */ -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial) -{ /* ftdi_HE_TIRA1_startup */ +/* Setup for the HE-TIRA1 device, which requires hardwired + * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_FT232BM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = B38400; priv->force_rtscts = 1; - - return (0); -} /* ftdi_HE_TIRA1_startup */ +} /* ftdi_HE_TIRA1_setup */ /* ftdi_shutdown is called from usbserial:usb_serial_disconnect @@ -2516,24 +2127,9 @@ static int __init ftdi_init (void) int retval; dbg("%s", __FUNCTION__); - retval = usb_serial_register(&ftdi_SIO_device); - if (retval) - goto failed_SIO_register; - retval = usb_serial_register(&ftdi_8U232AM_device); - if (retval) - goto failed_8U232AM_register; - retval = usb_serial_register(&ftdi_FT232BM_device); - if (retval) - goto failed_FT232BM_register; - retval = usb_serial_register(&ftdi_FT2232C_device); - if (retval) - goto failed_FT2232C_register; - retval = usb_serial_register(&ftdi_USB_UIRT_device); - if (retval) - goto failed_USB_UIRT_register; - retval = usb_serial_register(&ftdi_HE_TIRA1_device); + retval = usb_serial_register(&ftdi_sio_device); if (retval) - goto failed_HE_TIRA1_register; + goto failed_sio_register; retval = usb_register(&ftdi_driver); if (retval) goto failed_usb_register; @@ -2541,18 +2137,8 @@ static int __init ftdi_init (void) info(DRIVER_VERSION ":" DRIVER_DESC); return 0; failed_usb_register: - usb_serial_deregister(&ftdi_HE_TIRA1_device); -failed_HE_TIRA1_register: - usb_serial_deregister(&ftdi_USB_UIRT_device); -failed_USB_UIRT_register: - usb_serial_deregister(&ftdi_FT2232C_device); -failed_FT2232C_register: - usb_serial_deregister(&ftdi_FT232BM_device); -failed_FT232BM_register: - usb_serial_deregister(&ftdi_8U232AM_device); -failed_8U232AM_register: - usb_serial_deregister(&ftdi_SIO_device); -failed_SIO_register: + usb_serial_deregister(&ftdi_sio_device); +failed_sio_register: return retval; } @@ -2563,12 +2149,7 @@ static void __exit ftdi_exit (void) dbg("%s", __FUNCTION__); usb_deregister (&ftdi_driver); - usb_serial_deregister (&ftdi_HE_TIRA1_device); - usb_serial_deregister (&ftdi_USB_UIRT_device); - usb_serial_deregister (&ftdi_FT2232C_device); - usb_serial_deregister (&ftdi_FT232BM_device); - usb_serial_deregister (&ftdi_8U232AM_device); - usb_serial_deregister (&ftdi_SIO_device); + usb_serial_deregister (&ftdi_sio_device); } -- cgit v1.2.3 From 7e33ae67815372a93e8e77624fd47e39a986415d Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 17:10:19 +0100 Subject: [PATCH] USB ftdi_sio: remove redundant TIOCMBIS and TIOCMBIC code ftdi_sio: Remove redundant handling of TIOCMBIS and TIOCMBIC ioctls as they are handled in the tty layer and never reach this driver. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 47 ------------------------------------------- 1 file changed, 47 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f843f735886..aad2f4d0e09 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1985,53 +1985,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne /* Based on code from acm.c and others */ switch (cmd) { - case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg("%s TIOCMBIS", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, HIGH)) < 0) { - err("Urb to set DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, HIGH)) < 0){ - err("Urb to set RTS failed"); - return(ret); - } - } - return(0); - break; - - case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg("%s TIOCMBIC", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, LOW)) < 0){ - err("Urb to unset DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, LOW)) < 0){ - err("Urb to unset RTS failed"); - return(ret); - } - } - return(0); - break; - - /* - * I had originally implemented TCSET{A,S}{,F,W} and - * TCGET{A,S} here separately, however when testing I - * found that the higher layers actually do the termios - * conversions themselves and pass the call onto - * ftdi_sio_set_termios. - * - */ - case TIOCGSERIAL: /* gets serial port data */ return get_serial_info(port, (struct serial_struct __user *) arg); -- cgit v1.2.3 From 16966f2ab7db7366855d1267071a3138ae127ff6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix ftdi_sio compiler warnings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aad2f4d0e09..0b03ddab53d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1978,8 +1978,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne { struct ftdi_private *priv = usb_get_serial_port_data(port); - int ret, mask; - dbg("%s cmd 0x%04x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ -- cgit v1.2.3 From 322a95bc8eba889d2f9d7222936d682c9aad8294 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:20:50 +0200 Subject: [PATCH] USB ATM: line speed measured in Kb not Kib Spotted by David Woodhouse. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 2 +- drivers/usb/atm/speedtch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index cbd4a7d25d0..8e184e2641c 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -427,7 +427,7 @@ static void cxacru_poll_status(struct cxacru_data *instance) atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424; atm_dev->signal = ATM_PHY_SIG_FOUND; - dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n", + dev_info(dev, "ADSL line: up (%d kb/s down | %d kb/s up)\n", buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]); break; diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 6a6eaa2a3b1..992db1c1683 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -480,7 +480,7 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_dev->signal = ATM_PHY_SIG_FOUND; atm_info(usbatm, - "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", + "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); } break; -- cgit v1.2.3 From cd5c08fb7b0d960b7cd48bc977feee7b3bd8b046 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:23:10 +0200 Subject: [PATCH] USB ATM: robustify poll throttling No functional change, but less likely to break in the future. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 992db1c1683..03a0e99a426 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -430,13 +430,11 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) ret = speedtch_read_status(instance); if (ret < 0) { atm_warn(usbatm, "error %d fetching device status\n", ret); - if (instance->poll_delay < MAX_POLL_DELAY) - instance->poll_delay *= 2; + instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY); return; } - if (instance->poll_delay > MIN_POLL_DELAY) - instance->poll_delay /= 2; + instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); -- cgit v1.2.3 From 1a7aad15ff93be104c8e0851a43b94f8ccd92225 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:37:56 +0200 Subject: [PATCH] USB ATM: fix line resync logic We map states 0x00 and 0x10 to the ATM_PHY_SIG_LOST flag. The current logic fails to resync the line if we get state 0x10 followed by 0x00, since we only resync the line when the state is 0x00 and the flag changed. Doubly fixed by (1) always resyncing the line when the state is 0x00 even if the state didn't change, and (2) keeping track of the last state, not just the flag. We do (2) as well as (1) in order to get better log messages. This is a tweaked version of the original patch by Aurelio Arroyo. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 55 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 03a0e99a426..d0cbbb7f038 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -100,6 +100,8 @@ struct speedtch_instance_data { struct work_struct status_checker; + unsigned char last_status; + int poll_delay; /* milliseconds */ struct timer_list resubmit_timer; @@ -423,7 +425,8 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; - int ret; + int down_speed, up_speed, ret; + unsigned char status; atm_dbg(usbatm, "%s entered\n", __func__); @@ -436,37 +439,34 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); - atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); + status = buf[OFFSET_7]; - switch (buf[OFFSET_7]) { - case 0: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + atm_dbg(usbatm, "%s: line state %02x\n", __func__, status); + + if ((status != instance->last_status) || !status) { + switch (status) { + case 0: atm_dev->signal = ATM_PHY_SIG_LOST; - atm_info(usbatm, "ADSL line is down\n"); - /* It'll never resync again unless we ask it to... */ + if (instance->last_status) + atm_info(usbatm, "ADSL line is down\n"); + /* It may never resync again unless we ask it to... */ ret = speedtch_start_synchro(instance); - } - break; + break; - case 0x08: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + case 0x08: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; atm_info(usbatm, "ADSL line is blocked?\n"); - } - break; + break; - case 0x10: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + case 0x10: atm_dev->signal = ATM_PHY_SIG_LOST; atm_info(usbatm, "ADSL line is synchronising\n"); - } - break; + break; - case 0x20: - if (atm_dev->signal != ATM_PHY_SIG_FOUND) { - int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) + case 0x20: + down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); - int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) + up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { @@ -480,15 +480,15 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_info(usbatm, "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); - } - break; + break; - default: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + default: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]); + atm_info(usbatm, "Unknown line state %02x\n", status); + break; } - break; + + instance->last_status = status; } } @@ -728,6 +728,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; + instance->last_status = 0xff; instance->poll_delay = MIN_POLL_DELAY; init_timer(&instance->resubmit_timer); -- cgit v1.2.3 From ead99eb00190a274e3b3666ecd431be12c2b7888 Mon Sep 17 00:00:00 2001 From: Thomas Winischhofer Date: Fri, 24 Jun 2005 18:44:20 +0200 Subject: [PATCH] USB: SiS USB Makefile fixes although 2.6.12 now contains the sisusb driver, it failes to build this driver due to a missing patch of the Makefile. From: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index d79cd218a55..284f95723ee 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_TEST) += misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ +obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ -- cgit v1.2.3 From ae0d6cceb20eec57e7196c22999c62c465ffd5bf Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 25 Jun 2005 14:32:59 -0700 Subject: [PATCH] USB: Patch to make usbmon to print control setup packets Make usbmon to print Setup packets of Control transfers. This is useful when debugging enumeration issues. This is a change to the trace format which is not fully compatible. A parser has to look at the data length word now. If that word is a character like 's', read setup packet before proceeding with data. I decided not to bump the API tag for this because not many such parsers exist at this point. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_text.c | 48 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 755a4570477..26266b30028 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -18,12 +18,17 @@ */ #define DATA_MAX 32 +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_MAX 8 + /* * This limit exists to prevent OOMs when the user process stops reading. */ #define EVENT_MAX 25 -#define PRINTF_DFL 120 +#define PRINTF_DFL 130 struct mon_event_text { struct list_head e_link; @@ -33,7 +38,9 @@ struct mon_event_text { unsigned int tstamp; int length; /* Depends on type: xfer length or act length */ int status; + char setup_flag; char data_flag; + unsigned char setup[SETUP_MAX]; unsigned char data[DATA_MAX]; }; @@ -64,6 +71,22 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long); * This is called with the whole mon_bus locked, so no additional lock. */ +static inline char mon_text_get_setup(struct mon_event_text *ep, + struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return 'D'; + if (urb->setup_packet == NULL) + return 'Z'; /* '0' would be not as pretty. */ + + memcpy(ep->setup, urb->setup_packet, SETUP_MAX); + return 0; +} + static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type) { @@ -90,7 +113,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, /* * Bulk is easy to shortcut reliably. - * XXX Control needs setup packet taken. * XXX Other pipe types need consideration. Currently, we overdo it * and collect garbage for them: better more than less. */ @@ -144,6 +166,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; + ep->setup_flag = mon_text_get_setup(ep, urb, ev_type); ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type); rp->nevents++; @@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf, default: /* PIPE_BULK */ utype = 'B'; } cnt += snprintf(pbuf + cnt, limit - cnt, - "%lx %u %c %c%c:%03u:%02u %d %d", + "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe), - ep->status, ep->length); + utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + + if (ep->setup_flag == 0) { /* Setup packet is present and captured */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " s %02x %02x %04x %04x %04x", + ep->setup[0], + ep->setup[1], + (ep->setup[3] << 8) | ep->setup[2], + (ep->setup[5] << 8) | ep->setup[4], + (ep->setup[7] << 8) | ep->setup[6]); + } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " %c __ __ ____ ____ ____", ep->setup_flag); + } else { /* No setup for this kind of URB */ + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status); + } + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length); if ((data_len = ep->length) > 0) { if (ep->data_flag == 0) { -- cgit v1.2.3 From 17f8bb7312fa9b00f80c3c0f8d5a5d698eb97bbd Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:12:24 +0300 Subject: [PATCH] USB: isp116x-hcd cleanup Sorry that it took so long. Here comes a cleanup patch that addresses the remarks by Alexey Dobriyan about gregkh-usb-usb-isp116x-hcd-add.patch EXCEPT the remark about the typecasting of mem_flags argument for kcalloc; this will be addressed in a later patch. OlavCleanup of isp116x-hcd. Signed off by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index ff0a168e8ee..3f2cea21efc 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -17,7 +17,7 @@ * The driver basically works. A number of people have used it with a range * of devices. * - *The driver passes all usbtests 1-14. + * The driver passes all usbtests 1-14. * * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. * And suspending/resuming of platform device works too. Suspend/resume @@ -229,7 +229,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) struct isp116x_ep *ep; struct urb *urb; struct ptd *ptd; - u16 toggle, dir, len; + u16 toggle = 0, dir = PTD_DIR_SETUP, len; for (ep = isp116x->atl_active; ep; ep = ep->active) { BUG_ON(list_empty(&ep->hep->urb_list)); @@ -251,8 +251,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) dir = PTD_DIR_OUT; break; case USB_PID_SETUP: - toggle = 0; - dir = PTD_DIR_SETUP; len = sizeof(struct usb_ctrlrequest); ep->data = urb->setup_packet; break; @@ -264,11 +262,9 @@ static void preproc_atl_queue(struct isp116x *isp116x) ? PTD_DIR_OUT : PTD_DIR_IN; break; default: - /* To please gcc */ - toggle = dir = 0; ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__, ep->nextpid); - BUG_ON(1); + BUG(); } ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); @@ -1054,7 +1050,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd, break; case GetHubStatus: DBG("GetHubStatus\n"); - *(__le32 *) buf = cpu_to_le32(0); + *(__le32 *) buf = 0; break; case GetPortStatus: DBG("GetPortStatus\n"); @@ -1810,9 +1806,9 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) ret = usb_suspend_device(hcd->self.root_hub, state); if (!ret) { dev->power.power_state = state; - INFO("%s suspended\n", (char *)hcd_name); + INFO("%s suspended\n", hcd_name); } else - ERR("%s suspend failed\n", (char *)hcd_name); + ERR("%s suspend failed\n", hcd_name); return ret; } -- cgit v1.2.3 From 5db539e49fc7471e23bf3c94ca304f008cb7b7f3 Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:25:36 +0300 Subject: [PATCH] USB: Fix kmalloc's flags type in USB Greg, This patch fixes the kmalloc() flags argument type in USB subsystem; hopefully all of its occurences. The patch was made against patch-2.6.12-git2 from Jun 20. Cleanup of flags for kmalloc() in USB subsystem. Signed-off-by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 2 +- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 8 ++++---- drivers/usb/core/message.c | 2 +- drivers/usb/core/urb.c | 4 ++-- drivers/usb/core/usb.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 9 +++++---- drivers/usb/gadget/ether.c | 18 +++++++++--------- drivers/usb/gadget/goku_udc.c | 6 +++--- drivers/usb/gadget/lh7a40x_udc.c | 6 +++--- drivers/usb/gadget/net2280.c | 6 +++--- drivers/usb/gadget/omap_udc.c | 6 +++--- drivers/usb/gadget/pxa2xx_udc.c | 6 +++--- drivers/usb/gadget/zero.c | 8 ++++---- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/ehci-sched.c | 19 +++++++++++-------- drivers/usb/host/hc_crisv10.c | 10 ++++++---- drivers/usb/host/isp116x-hcd.c | 4 ++-- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-mem.c | 4 ++-- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/net/kaweth.c | 4 ++-- 24 files changed, 71 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b7827df21f4..fc15b4acc8a 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 83e732a0d64..8616356f55e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1112,7 +1112,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, int mem_flags) +static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8dc13cde2f7..67db4a999b9 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, int mem_flags); + int (*submit_urb) (struct urb *urb, unsigned mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -200,7 +200,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags); + unsigned mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -247,7 +247,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - int mem_flags, dma_addr_t *dma); + unsigned mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f50aaf25c98..a428ef479bd 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -320,7 +320,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - int mem_flags + unsigned mem_flags ) { int i; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 0faf18d511d..c0feee25ff0 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, int mem_flags) +struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, int mem_flags) +int usb_submit_urb(struct urb *urb, unsigned mem_flags) { int pipe, temp, max; struct usb_device *dev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a3c42203213..7713a605fce 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1129,7 +1129,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4d692670f28..583db7c38cf 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, int mem_flags) +dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int mem_flags + unsigned mem_flags ) { char *retval; struct dummy_ep *ep; @@ -540,7 +540,8 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) } static int -dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) +dummy_queue (struct usb_ep *_ep, struct usb_request *_req, + unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -998,7 +999,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct dummy *dum; struct urbp *urbp; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 5bb53ae8896..00a5d256626 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, int gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); +static void eth_start (struct eth_dev *dev, unsigned gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); static int -set_ether_config (struct eth_dev *dev, int gfp_flags) +set_ether_config (struct eth_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1079,7 +1079,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1596,7 +1596,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1722,7 +1722,7 @@ clean: } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, int gfp_flags) + unsigned n, unsigned gfp_flags) { unsigned i; struct usb_request *req; @@ -1761,7 +1761,7 @@ extra: return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) { int status; @@ -1777,7 +1777,7 @@ fail: return status; } -static void rx_fill (struct eth_dev *dev, int gfp_flags) +static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) { struct usb_request *req; unsigned long flags; @@ -2022,7 +2022,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, int gfp_flags) +static void eth_start (struct eth_dev *dev, unsigned gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ed773a9111d..eaab26f4ed3 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, int gfp_flags) +goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ finished: /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct goku_request *req; struct goku_ep *ep; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index df75ab65a5e..4842577789c 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, int gfp_flags) + dma_addr_t * dma, unsigned gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 13a3dbc9949..234a1a97b84 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, int gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index a2b812af6e6..c906d675ef4 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, int gfp_flags) +omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -937,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 6a0b957af33..1507738337c 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, int gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { char *retval; @@ -874,7 +874,7 @@ done: /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index a6e035e2447..bb9b2d94eed 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, int gfp_flags) +source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, int gfp_flags) +set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, int gfp_flags) +set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35248a37b71..149b13fc0a7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -960,7 +960,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 45d89a7083b..d74b2d68a50 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -898,7 +898,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index c2104cad403..9af4f64532a 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -588,7 +588,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { unsigned epnum; unsigned long flags; @@ -633,7 +633,7 @@ done: /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (int mem_flags) +iso_stream_alloc (unsigned mem_flags) { struct ehci_iso_stream *stream; @@ -846,7 +846,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, int mem_flags) +iso_sched_alloc (unsigned packets, unsigned mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -919,7 +919,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_itd *itd; @@ -1412,7 +1412,8 @@ itd_complete ( /*-------------------------------------------------------------------------*/ -static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1523,7 +1524,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_sitd *sitd; @@ -1772,7 +1773,8 @@ sitd_complete ( } -static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1822,7 +1824,8 @@ done: #else static inline int -sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { ehci_dbg (ehci, "split iso support is disabled\n"); return -ENOSYS; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index d9883d774d3..81f8f6b7fdc 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -463,7 +463,8 @@ static void etrax_usb_free_epid(int epid); static int etrax_remove_from_sb_list(struct urb *urb); -static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma); +static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma); static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid); @@ -476,7 +477,7 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb); static int etrax_usb_submit_intr_urb(struct urb *urb); static int etrax_usb_submit_isoc_urb(struct urb *urb); -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags); +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags); static int etrax_usb_unlink_urb(struct urb *urb, int status); static int etrax_usb_get_frame_number(struct usb_device *usb_dev); @@ -1262,7 +1263,7 @@ static int etrax_usb_allocate_epid(void) return -1; } -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags) +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags) { etrax_hc_t *hc; int ret = -EINVAL; @@ -4277,7 +4278,8 @@ etrax_usb_bulk_eot_timer_func(unsigned long dummy) } static void* -etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma) +etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma) { return kmalloc(size, mem_flags); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 3f2cea21efc..50b1970fe6b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -693,7 +693,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags) + unsigned mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; @@ -715,7 +715,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } /* avoid all allocations within spinlocks: request or endpoint */ if (!hep->hcpriv) { - ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags); + ep = kcalloc(1, sizeof *ep, mem_flags); if (!ep) return -ENOMEM; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 13cd2177b55..0375097850e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 23735a36af0..fd3c4d3714b 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -84,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, int mem_flags) +td_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, int mem_flags) +ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 6c3f910bc30..7a890a65f55 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -815,7 +815,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5f18084a116..bbb36cd6ed6 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1164,7 +1164,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, int mem_flags) + struct urb *urb, unsigned mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fd6ff4cb2c6..7ffa99b9760 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -477,7 +477,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, int); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); /**************************************************************** int_callback @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - int mem_flags) + unsigned mem_flags) { int result; -- cgit v1.2.3 From 30e695986679ac2d2354fc1634e8cb931bb47785 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 26 Jun 2005 17:18:46 -0700 Subject: [PATCH] USB: net2280 warning fix drivers/usb/gadget/net2280.c: In function 'show_registers': drivers/usb/gadget/net2280.c:1501: warning: assignment discards qualifiers from pointer target type Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 234a1a97b84..477fab2e74d 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1490,7 +1490,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf) unsigned long flags; int i; u32 t1, t2; - char *s; + const char *s; dev = dev_get_drvdata (_dev); next = buf; -- cgit v1.2.3 From 99f83c9c9ac994c844ecf3e64e848c2f8dd7dfe0 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Mon, 27 Jun 2005 11:48:26 -0600 Subject: [PATCH] USB: add driver for Keyspan Digital Remote This driver is a basic keypress input driver for the Keyspan Digital Remote with part number UIA-11. Currently there is an older remote with part number UIA-10 which isn't supported by this driver. Support for the older UIA-10 could be added but a binary file is required to be download to the device, and I don't have that file. I also don't have a UIA-10 device so I wouldn't be able to test any of the changes. Signed-off-by: Michael Downey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 13 + drivers/usb/input/Makefile | 1 + drivers/usb/input/keyspan_remote.c | 633 +++++++++++++++++++++++++++++++++++++ 3 files changed, 647 insertions(+) create mode 100644 drivers/usb/input/keyspan_remote.c (limited to 'drivers') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fd59f6bdd67..298e4a25e3d 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -259,3 +259,16 @@ config USB_ATI_REMOTE To compile this driver as a module, choose M here: the module will be called ati_remote. +config USB_KEYSPAN_REMOTE + tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" + depends on USB && INPUT && EXPERIMENTAL + ---help--- + Say Y here if you want to use a Keyspan DMR USB remote control. + Currently only the UIA-11 type of receiver has been tested. The tag + on the receiver that connects to the USB port should have a P/N that + will tell you what type of DMR you have. The UIA-10 type is not + supported at this time. This driver maps all buttons to keypress + events. + + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 831b2b0f1f0..f1547be632d 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c new file mode 100644 index 00000000000..67dc9368520 --- /dev/null +++ b/drivers/usb/input/keyspan_remote.c @@ -0,0 +1,633 @@ +/* + * keyspan_remote: USB driver for the Keyspan DMR + * + * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * This driver has been put together with the support of Innosys, Inc. + * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Michael Downey " +#define DRIVER_DESC "Driver for the USB Keyspan remote control." +#define DRIVER_LICENSE "GPL" + +/* Parameters that can be passed to the driver. */ +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +/* Vendor and product ids */ +#define USB_KEYSPAN_VENDOR_ID 0x06CD +#define USB_KEYSPAN_PRODUCT_UIA11 0x0202 + +/* Defines for converting the data from the remote. */ +#define ZERO 0x18 +#define ZERO_MASK 0x1F /* 5 bits for a 0 */ +#define ONE 0x3C +#define ONE_MASK 0x3F /* 6 bits for a 1 */ +#define SYNC 0x3F80 +#define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */ +#define STOP 0x00 +#define STOP_MASK 0x1F /* 5 bits for the STOP sequence */ +#define GAP 0xFF + +#define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ + +/* table of devices that work with this driver */ +static struct usb_device_id keyspan_table[] = { + { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, + { } /* Terminating entry */ +}; + +/* Structure to store all the real stuff that a remote sends to us. */ +struct keyspan_message { + u16 system; + u8 button; + u8 toggle; +}; + +/* Structure used for all the bit testing magic needed to be done. */ +struct bit_tester { + u32 tester; + int len; + int pos; + int bits_left; + u8 buffer[32]; +}; + +/* Structure to hold all of our driver specific stuff */ +struct usb_keyspan { + char name[128]; + char phys[64]; + struct usb_device* udev; + struct input_dev input; + struct usb_interface* interface; + struct usb_endpoint_descriptor* in_endpoint; + struct urb* irq_urb; + int open; + dma_addr_t in_dma; + unsigned char* in_buffer; + + /* variables used to parse messages from remote. */ + struct bit_tester data; + int stage; + int toggle; +}; + +/* + * Table that maps the 31 possible keycodes to input keys. + * Currently there are 15 and 17 button models so RESERVED codes + * are blank areas in the mapping. + */ +static int keyspan_key_table[] = { + KEY_RESERVED, /* 0 is just a place holder. */ + KEY_RESERVED, + KEY_STOP, + KEY_PLAYCD, + KEY_RESERVED, + KEY_PREVIOUSSONG, + KEY_REWIND, + KEY_FORWARD, + KEY_NEXTSONG, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PAUSE, + KEY_VOLUMEUP, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_VOLUMEDOWN, + KEY_RESERVED, + KEY_UP, + KEY_RESERVED, + KEY_MUTE, + KEY_LEFT, + KEY_ENTER, + KEY_RIGHT, + KEY_RESERVED, + KEY_RESERVED, + KEY_DOWN, + KEY_RESERVED, + KEY_KPASTERISK, + KEY_RESERVED, + KEY_MENU +}; + +static struct usb_driver keyspan_driver; + +/* + * Debug routine that prints out what we've received from the remote. + */ +static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ +{ + char codes[4*RECV_SIZE]; + int i; + + for (i = 0; i < RECV_SIZE; i++) { + snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); + } + + dev_info(&dev->udev->dev, "%s\n", codes); +} + +/* + * Routine that manages the bit_tester structure. It makes sure that there are + * at least bits_needed bits loaded into the tester. + */ +static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) +{ + if (dev->data.bits_left >= bits_needed) + return(0); + + /* + * Somehow we've missed the last message. The message will be repeated + * though so it's not too big a deal + */ + if (dev->data.pos >= dev->data.len) { + dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", + __FUNCTION__, dev->data.pos, dev->data.len); + return(-1); + } + + /* Load as much as we can into the tester. */ + while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) && + (dev->data.pos < dev->data.len)) { + dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left); + dev->data.bits_left += 8; + } + + return(0); +} + +/* + * Routine that handles all the logic needed to parse out the message from the remote. + */ +static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) +{ + int i; + int found = 0; + struct keyspan_message message; + + switch(remote->stage) { + case 0: + /* + * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler. + * So the first byte that isn't a FF should be the start of a new message. + */ + for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i); + + if (i < RECV_SIZE) { + memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE); + remote->data.len = RECV_SIZE; + remote->data.pos = 0; + remote->data.tester = 0; + remote->data.bits_left = 0; + remote->stage = 1; + } + break; + + case 1: + /* + * Stage 1 we should have 16 bytes and should be able to detect a + * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + found = 0; + while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) { + for (i = 0; i < 8; ++i) { + if (keyspan_load_tester(remote, 14) != 0) { + remote->stage = 0; + return; + } + + if ((remote->data.tester & SYNC_MASK) == SYNC) { + remote->data.tester = remote->data.tester >> 14; + remote->data.bits_left -= 14; + found = 1; + break; + } else { + remote->data.tester = remote->data.tester >> 1; + --remote->data.bits_left; + } + } + } + + if (!found) { + remote->stage = 0; + remote->data.len = 0; + } else { + remote->stage = 2; + } + break; + + case 2: + /* + * Stage 2 we should have 24 bytes which will be enough for a full + * message. We need to parse out the system code, button code, + * toggle code, and stop. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + message.system = 0; + for (i = 0; i < 9; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.system = message.system << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.system = (message.system << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in system data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + message.button = 0; + for (i = 0; i < 5; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.button = message.button << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.button = (message.button << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in button data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + keyspan_load_tester(remote, 6); + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.toggle = 0; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.toggle = 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + } + + keyspan_load_tester(remote, 5); + if ((remote->data.tester & STOP_MASK) == STOP) { + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else { + err("Bad message recieved, no stop bit found.\n"); + } + + dev_dbg(&remote->udev, + "%s found valid message: system: %d, button: %d, toggle: %d\n", + __FUNCTION__, message.system, message.button, message.toggle); + + if (message.toggle != remote->toggle) { + input_regs(&remote->input, regs); + input_report_key(&remote->input, keyspan_key_table[message.button], 1); + input_report_key(&remote->input, keyspan_key_table[message.button], 0); + input_sync(&remote->input); + remote->toggle = message.toggle; + } + + remote->stage = 0; + break; + } +} + +/* + * Routine for sending all the initialization messages to the remote. + */ +static int keyspan_setup(struct usb_device* dev) +{ + int retval = 0; + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); + return(retval); +} + +/* + * Routine used to handle a new message that has come in. + */ +static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) +{ + struct usb_keyspan *dev = urb->context; + int retval; + + /* Check our status in case we need to bail out early. */ + switch (urb->status) { + case 0: + break; + + /* Device went away so don't keep trying to read from it. */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + goto resubmit; + break; + } + + if (debug) + keyspan_print(dev); + + keyspan_check_data(dev, regs); + +resubmit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); +} + +static int keyspan_open(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (remote->open++) + return 0; + + remote->irq_urb->dev = remote->udev; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { + remote->open--; + return -EIO; + } + + return 0; +} + +static void keyspan_close(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (!--remote->open) + usb_kill_urb(remote->irq_urb); +} + +/* + * Routine that sets up the driver to handle a specific USB device detected on the bus. + */ +static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + int i; + int retval = -ENOMEM; + char path[64]; + char *buf; + struct usb_keyspan *remote = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) || + (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) ) + return -ENODEV; + + /* allocate memory for our device state and initialize it */ + remote = kmalloc(sizeof(*remote), GFP_KERNEL); + if (remote == NULL) { + err("Out of memory\n"); + goto error; + } + memset(remote, 0x00, sizeof(*remote)); + + remote->udev = udev; + remote->interface = interface; + remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ + + /* set up the endpoint information */ + /* use only the first in interrupt endpoint */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!remote->in_endpoint && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + remote->in_endpoint = endpoint; + + remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto error; + } + } + } + + if (!remote->in_endpoint) { + err("Could not find interrupt input endpoint.\n"); + retval = -ENODEV; + goto error; + } + + remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!remote->irq_urb) { + err("Failed to allocate urb.\n"); + retval = -ENOMEM; + goto error; + } + + retval = keyspan_setup(remote->udev); + if (retval) { + err("Failed to setup device.\n"); + retval = -ENODEV; + goto error; + } + + /* + * Setup the input system with the bits we are going to be reporting + */ + remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < 32; ++i) { + if (keyspan_key_table[i] != KEY_RESERVED) { + set_bit(keyspan_key_table[i], remote->input.keybit); + } + } + + remote->input.private = remote; + remote->input.open = keyspan_open; + remote->input.close = keyspan_close; + + usb_make_path(remote->udev, path, 64); + sprintf(remote->phys, "%s/input0", path); + + remote->input.name = remote->name; + remote->input.phys = remote->phys; + remote->input.id.bustype = BUS_USB; + remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); + remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); + remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + return -ENOMEM; + } + + if (remote->udev->descriptor.iManufacturer && + usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(remote->name, buf); + + if (remote->udev->descriptor.iProduct && + usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) + sprintf(remote->name, "%s %s", remote->name, buf); + + if (!strlen(remote->name)) + sprintf(remote->name, "USB Keyspan Remote %04x:%04x", + remote->input.id.vendor, remote->input.id.product); + + kfree(buf); + + /* + * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() + */ + usb_fill_int_urb(remote->irq_urb, + remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), + remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, + remote->in_endpoint->bInterval); + remote->irq_urb->transfer_dma = remote->in_dma; + remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* we can register the device now, as it is ready */ + input_register_device(&remote->input); + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, remote); + + /* let the user know what node this device is now attached to */ + info("connected: %s on %s", remote->name, path); + return 0; + +error: + /* + * In case of error we need to clean up any allocated buffers + */ + if (remote->irq_urb) + usb_free_urb(remote->irq_urb); + + if (remote->in_buffer) + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + + if (remote) + kfree(remote); + + return retval; +} + +/* + * Routine called when a device is disconnected from the USB. + */ +static void keyspan_disconnect(struct usb_interface *interface) +{ + struct usb_keyspan *remote; + + /* prevent keyspan_open() from racing keyspan_disconnect() */ + lock_kernel(); + + remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ + input_unregister_device(&remote->input); + usb_kill_urb(remote->irq_urb); + usb_free_urb(remote->irq_urb); + usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + } + + unlock_kernel(); + + info("USB Keyspan now disconnected"); +} + +/* + * Standard driver set up sections + */ +static struct usb_driver keyspan_driver = +{ + .owner = THIS_MODULE, + .name = "keyspan_remote", + .probe = keyspan_probe, + .disconnect = keyspan_disconnect, + .id_table = keyspan_table +}; + +static int __init usb_keyspan_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&keyspan_driver); + if (result) + err("usb_register failed. Error number %d\n", result); + + return result; +} + +static void __exit usb_keyspan_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&keyspan_driver); +} + +module_init(usb_keyspan_init); +module_exit(usb_keyspan_exit); + +MODULE_DEVICE_TABLE(usb, keyspan_table); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); -- cgit v1.2.3 From b2134bcd2e1bf989e0566dd1b0e59a792722b671 Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Fri, 24 Jun 2005 22:20:35 -0700 Subject: [PATCH] USB: coverity: (desc->bitmap)[] overrun fix The length of the array desc->bitmap is 3, and not 4: Definitions involved: In drivers/usb/core/hcd.h 464 #define bitmap DeviceRemovable In drivers/usb/host/ohci-hub.c 395 struct usb_hub_descriptor *desc In drivers/usb/core/hub.h 130 struct usb_hub_descriptor { 131 __u8 bDescLength; 132 __u8 bDescriptorType; 133 __u8 bNbrPorts; 134 __u16 wHubCharacteristics; 135 __u8 bPwrOn2PwrGood; 136 __u8 bHubContrCurrent; 137 /* add 1 bit for hub status change; round to bytes */ 138 __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; 139 __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; 140 } __attribute__ ((packed)); In include/linux/usb.h 306 #define USB_MAXCHILDREN (16) This defect was found automatically by Coverity Prevent, a static analysis tool. (akpm: this code should be shot. Field `bitmap' doesn't exist in struct usb_hub_descriptor. And this .c file is #included in drivers/usb/host/ohci-hcd.c, and someone somewhere #defines `bitmap' to `DeviceRemovable'. >From a maintainability POV it would be better to memset the whole array beforehand - I changed the patch to do that) Signed-off-by: Zaur Kambarov Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index e2fc4129dfc..83ca4549a50 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -419,10 +419,11 @@ ohci_hub_descriptor ( /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); + memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); desc->bitmap [0] = rh & RH_B_DR; if (ports > 7) { desc->bitmap [1] = (rh & RH_B_DR) >> 8; - desc->bitmap [2] = desc->bitmap [3] = 0xff; + desc->bitmap [2] = 0xff; } else desc->bitmap [1] = 0xff; } -- cgit v1.2.3 From 8fd6db47b90c7ecac32e3211f771849e148bdb07 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add LD devices to hid blacklist below you will find one patch to hid-core.c, which lets usbhid ignore our HID devices. It would be nice, if you can apply it. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 100b49bd1d3..2350e7a5ad7 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1428,6 +1428,19 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 +#define USB_VENDOR_ID_LD 0x0f11 +#define USB_DEVICE_ID_CASSY 0x1000 +#define USB_DEVICE_ID_POCKETCASSY 0x1010 +#define USB_DEVICE_ID_MOBILECASSY 0x1020 +#define USB_DEVICE_ID_JWM 0x1080 +#define USB_DEVICE_ID_DMMP 0x1081 +#define USB_DEVICE_ID_UMIP 0x1090 +#define USB_DEVICE_ID_VIDEOCOM 0x1200 +#define USB_DEVICE_ID_COM3LAB 0x2000 +#define USB_DEVICE_ID_TELEPORT 0x2010 +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 +#define USB_DEVICE_ID_POWERCONTROL 0x2030 + /* * Alphabetically sorted blacklist by quirk type. @@ -1463,6 +1476,17 @@ static struct hid_blacklist { { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From b9df978f1974fea373741367b5d79a2ed3b7dcf9 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Jun 2005 16:30:24 +0200 Subject: [PATCH] USB: SN9C10x driver updates SN9C10x driver updates. Changes: + new, - removed, * cleanup, @ bugfix @ Remove bad get_ctrl()'s * Documentation updates + Add 0x0c45/0x602d to the list of SN9C10x based devices + Add support for OV7630 image sensors Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/Makefile | 2 +- drivers/usb/media/sn9c102.h | 2 +- drivers/usb/media/sn9c102_core.c | 2 +- drivers/usb/media/sn9c102_ov7630.c | 394 +++++++++++++++++++++++++++++++++ drivers/usb/media/sn9c102_sensor.h | 16 +- drivers/usb/media/sn9c102_tas5110c1b.c | 21 +- drivers/usb/media/sn9c102_tas5130d1b.c | 27 +-- 7 files changed, 413 insertions(+), 51 deletions(-) create mode 100644 drivers/usb/media/sn9c102_ov7630.c (limited to 'drivers') diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 2b76df7005f..d83adffa925 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Media drivers # -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index 8b8a4c8743f..e5cea0e2eb5 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -56,7 +56,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.24" +#define SN9C102_MODULE_VERSION "1:1.24a" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24) enum sn9c102_bridge { diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index 31d57400d5b..cf8cfbabefd 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam, } -static int +int sn9c102_i2c_try_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 address, u8 value) { diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c new file mode 100644 index 00000000000..d27c5aedeaf --- /dev/null +++ b/drivers/usb/media/sn9c102_ov7630.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * + * Controllers * + * * + * Copyright (C) 2005 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor ov7630; + + +static int ov7630_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); + + err += sn9c102_i2c_write(cam, 0x12, 0x8d); + err += sn9c102_i2c_write(cam, 0x11, 0x00); + err += sn9c102_i2c_write(cam, 0x15, 0x34); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1c); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x06); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x20, 0x44); + err += sn9c102_i2c_write(cam, 0x23, 0xee); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0x9a); + err += sn9c102_i2c_write(cam, 0x28, 0x20); + err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2f, 0x3d); + err += sn9c102_i2c_write(cam, 0x30, 0x24); + err += sn9c102_i2c_write(cam, 0x32, 0x86); + err += sn9c102_i2c_write(cam, 0x60, 0xa9); + err += sn9c102_i2c_write(cam, 0x61, 0x42); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x88); + err += sn9c102_i2c_write(cam, 0x70, 0x0b); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x74, 0x21); + err += sn9c102_i2c_write(cam, 0x7d, 0xf7); + + return err; +} + + +static int ov7630_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); + err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x02, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x00, ctrl->value); + break; + case V4L2_CID_CONTRAST: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x05, 0x00); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, ctrl->value); + break; + case V4L2_CID_SATURATION: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); + break; + case V4L2_CID_HUE: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x04, 0x00); + break; + case V4L2_CID_DO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); + break; + case V4L2_CID_WHITENESS: + err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09); + break; + case V4L2_CID_AUTOGAIN: + err += sn9c102_i2c_write(cam, 0x13, ctrl->value); + break; + case V4L2_CID_VFLIP: + err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); + break; + case V4L2_CID_BLACK_LEVEL: + err += sn9c102_i2c_write(cam, 0x25, ctrl->value); + break; + case SN9C102_V4L2_CID_BRIGHT_LEVEL: + err += sn9c102_i2c_write(cam, 0x24, ctrl->value); + break; + case SN9C102_V4L2_CID_GAMMA: + err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); + break; + case SN9C102_V4L2_CID_BAND_FILTER: + err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static int ov7630_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &ov7630; + int err = 0; + u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static int ov7630_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) + err += sn9c102_write_reg(cam, 0x20, 0x19); + else + err += sn9c102_write_reg(cam, 0x50, 0x19); + + return err; +} + + +static struct sn9c102_sensor ov7630 = { + .name = "OV7630", + .maintainer = "Luca Risolia ", + .sysfs_ops = SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x21, + .init = &ov7630_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x14, + .flags = 0, + }, + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "hue", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "saturation", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x08, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x000, + .maximum = 0x3ff, + .step = 0x001, + .default_value = 0x83<<2, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x3a, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x77, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0xa0, + .flags = 0, + }, + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: blue", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_WHITENESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: red", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain & exposure mode", + .minimum = 0x00, + .maximum = 0x03, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLACK_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "black pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x8a, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "bright pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x10, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BAND_FILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "band filter", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "rgb gamma", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .set_ctrl = &ov7630_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &ov7630_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &ov7630_set_pix_format +}; + + +int sn9c102_probe_ov7630(struct sn9c102_device* cam) +{ + int err = 0; + + sn9c102_attach_sensor(cam, &ov7630); + + if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f && + le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c) + return -ENODEV; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + + if (err) + return -EIO; + + err += sn9c102_i2c_write(cam, 0x0b, 0); + if (err) + return -ENODEV; + + return 0; +} diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 6a7adebcb4b..a45166c3488 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -64,6 +64,7 @@ struct sn9c102_sensor; */ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); +extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); @@ -80,6 +81,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -103,7 +105,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ - { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ + { USB_DEVICE(0x0c45, 0x602d), }, \ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ { USB_DEVICE(0x0c45, 0x6080), }, \ { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \ @@ -145,6 +148,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ */ /* The "try" I2C I/O versions are used when probing the sensor */ +extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, + u8 address, u8 value); extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); @@ -201,6 +206,8 @@ enum sn9c102_i2c_interface { SN9C102_I2C_3WIRES, }; +#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 + struct sn9c102_sensor { char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ @@ -243,7 +250,7 @@ struct sn9c102_sensor { sensor according to the default configuration structures below. */ - struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; /* Optional list of default controls, defined as indicated in the V4L2 API. Menu type controls are not handled by this interface. @@ -356,7 +363,7 @@ struct sn9c102_sensor { core module to store successfully updated values of the above settings, for rollbacks..etc..in case of errors during atomic I/O */ - struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; struct v4l2_rect _rect; }; @@ -367,5 +374,8 @@ struct sn9c102_sensor { #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 +#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 +#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 +#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 #endif /* _SN9C102_SENSOR_H_ */ diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c index 690d6219227..8775999b5af 100644 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ b/drivers/usb/media/sn9c102_tas5110c1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5110c1b; -static struct v4l2_control tas5110c1b_gain; - static int tas5110c1b_init(struct sn9c102_device* cam) { @@ -46,21 +44,6 @@ static int tas5110c1b_init(struct sn9c102_device* cam) } -static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5110c1b_gain.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -68,8 +51,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5110c1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +129,6 @@ static struct sn9c102_sensor tas5110c1b = { .height = 288, }, }, - .get_ctrl = &tas5110c1b_get_ctrl, .set_crop = &tas5110c1b_set_crop, .pix_format = { .width = 352, diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c index b378e941bbe..927eafdd8c7 100644 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ b/drivers/usb/media/sn9c102_tas5130d1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5130d1b; -static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure; - static int tas5130d1b_init(struct sn9c102_device* cam) { @@ -44,24 +42,6 @@ static int tas5130d1b_init(struct sn9c102_device* cam) } -static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5130d1b_gain.value; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = tas5130d1b_exposure.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -69,12 +49,10 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5130d1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; case V4L2_CID_EXPOSURE: - if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value))) - tas5130d1b_exposure.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +125,6 @@ static struct sn9c102_sensor tas5130d1b = { .flags = 0, }, }, - .get_ctrl = &tas5130d1b_get_ctrl, .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { -- cgit v1.2.3 From 05f33400307cfe9d89dbeca659731b9055fefbf8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:15:32 +0100 Subject: [PATCH] USB: gadget/ether fixes Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 00a5d256626..b5647b50336 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2428,7 +2428,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ -#ifdef DEV_CONFIG_CDC +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, STATUS_BYTECOUNT, GFP_KERNEL); -- cgit v1.2.3 From e828264ee797d40b1df99fe88c6acfc0f36df639 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:20:29 +0100 Subject: [PATCH] USB: gadget/ether build fixes. I also needed the following on 2.6.13-rc1 without CONFIG_USB_ETH_RNDIS, symbol fs_status_desc isn't available in that case on PXA255. This builds both with and without ETH_RNDIS, but I haven't actually tested either. Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index b5647b50336..8509e955007 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -954,6 +954,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* status endpoint used for RNDIS and (optionally) CDC */ if (!subset_active(dev) && dev->status_ep) { dev->status = ep_desc (gadget, &hs_status_desc, @@ -967,6 +968,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) goto done; } } +#endif dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; -- cgit v1.2.3 From 1d7beee3d4b4ae7faa881ef05ff5d94a125ed8a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:00:56 -0700 Subject: [PATCH] USB: omap_udc tweaks Minor OMAP updates that somehow got dropped from previous patches. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index c906d675ef4..ff5533e6956 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2908,6 +2908,7 @@ static int __exit omap_udc_remove(struct device *dev) * make host resumes and VBUS detection trigger OMAP wakeup events; that * may involve talking to an external transceiver (e.g. isp1301). */ + static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { u32 devstat; @@ -2936,8 +2937,6 @@ static int omap_udc_resume(struct device *dev, u32 level) return 0; DBG("resume + wakeup/SRP\n"); - udc->gadget.dev.parent->power.power_state = PMSG_ON; - udc->gadget.dev.power.power_state = PMSG_ON; omap_pullup(&udc->gadget, 1); /* maybe the host would enumerate us if we nudged it */ -- cgit v1.2.3 From b404a5b02abf84812e5333bda201af464925d7a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 06:59:14 -0700 Subject: [PATCH] USB: ohci-omap pm updates The recent "pm_message_t" changes removed functionality from the Linux PM framework. This patch removes it from the OMAP OHCI too, removing the distinction between (previous) PM_SUSPEND_MEM and PM_SUSPEND_DISK state transitions ... now the only suspend semantics supportable are what was previously PM_SUSPEND_DISK (4) and is now "PMSG_SUSPEND" (3). From: Todd Poynor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 53 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b62d6993769..5cde76faab9 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -456,34 +456,22 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) #ifdef CONFIG_PM -/* states match PCI usage, always suspending the root hub except that - * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). - * - * FIXME: above comment is not right, and code is wrong, too :-(. - */ - -static int ohci_omap_suspend(struct device *dev, pm_message_t state, u32 level) +static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; if (level != SUSPEND_POWER_DOWN) return 0; - if (state <= dev->power.power_state) - return 0; - dev_dbg(dev, "suspend to %d\n", state); down(&ohci_to_hcd(ohci)->self.root_hub->serialize); status = ohci_hub_suspend(ohci_to_hcd(ohci)); if (status == 0) { - if (state >= 4) { - omap_ohci_clock_power(0); - ohci_to_hcd(ohci)->self.root_hub->state = - USB_STATE_SUSPENDED; - state = 4; - } + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->self.root_hub->state = + USB_STATE_SUSPENDED; ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = state; + dev->power.power_state = PMSG_SUSPEND; } up(&ohci_to_hcd(ohci)->self.root_hub->serialize); return status; @@ -497,29 +485,20 @@ static int ohci_omap_resume(struct device *dev, u32 level) if (level != RESUME_POWER_ON) return 0; - switch (dev->power.power_state) { - case 0: - break; - case 4: - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - omap_ohci_clock_power(1); - /* FALLTHROUGH */ - default: - dev_dbg(dev, "resume from %d\n", dev->power.power_state); + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + omap_ohci_clock_power(1); #ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); #else - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_resume(ohci_to_hcd(ohci)); - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); + down(&ohci_to_hcd(ohci)->self.root_hub->serialize); + status = ohci_hub_resume(ohci_to_hcd(ohci)); + up(&ohci_to_hcd(ohci)->self.root_hub->serialize); #endif - if (status == 0) - dev->power.power_state = 0; - break; - } + if (status == 0) + dev->power.power_state = PMSG_ON; return status; } -- cgit v1.2.3 From edfd6aee1f073ae645bd3e60ef96090fc9f0957b Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:03:10 -0700 Subject: [PATCH] USB: fix ohci merge glitch A patch re-organizing some parts of root hub initialization deleted the code initializing the bus-neutral reboot/shutdown notifier for OHCI. This patch just restores that deleted code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0375097850e..68decab280d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -673,8 +673,10 @@ retry: ohci_dump (ohci, 1); - if (ohci_to_hcd(ohci)->self.root_hub == NULL) + if (ohci_to_hcd(ohci)->self.root_hub == NULL) { + register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); + } return 0; } -- cgit v1.2.3 From a3fdf4ebe016ba756de3ca29a2a6117e9acd721c Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: export usb_get_intf() and usb_put_intf() Export usb_get_intf and usb_put_intf so that modules can increase usb interface reference counts. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7713a605fce..99c85d2f92d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1532,6 +1532,9 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_disabled); +EXPORT_SYMBOL_GPL(usb_get_intf); +EXPORT_SYMBOL_GPL(usb_put_intf); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); -- cgit v1.2.3 From 83ef344a7539aa55a787790bc036f0bf3466e191 Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix usb reference count bug in cdc-acm driver This increases the reference count on the usb cdc acm control interface which is referred to by the tty interface provided by the driver. This allows the deferred removal of the tty after the physical device is disconnected if the tty is held open at the time of disconnection. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 69e859e0f51..adff5a77e31 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -422,6 +422,17 @@ bail_out: return -EIO; } +static void acm_tty_unregister(struct acm *acm) +{ + tty_unregister_device(acm_tty_driver, acm->minor); + usb_put_intf(acm->control); + acm_table[acm->minor] = NULL; + usb_free_urb(acm->ctrlurb); + usb_free_urb(acm->readurb); + usb_free_urb(acm->writeurb); + kfree(acm); +} + static void acm_tty_close(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; @@ -436,14 +447,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); usb_kill_urb(acm->readurb); - } else { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); - } + } else + acm_tty_unregister(acm); } up(&open_sem); } @@ -905,7 +910,8 @@ skip_normal_probe: usb_driver_claim_interface(&acm_driver, data_interface, acm); - tty_register_device(acm_tty_driver, minor, &intf->dev); + usb_get_intf(control_interface); + tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); @@ -954,12 +960,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_driver_release_interface(&acm_driver, acm->data); if (!acm->used) { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); + acm_tty_unregister(acm); up(&open_sem); return; } -- cgit v1.2.3 From 2824bd250f0be1551747cc3ed5ae07facc285b57 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add ldusb driver The following driver provides complete interrupt-in and interrupt-out reports (raw data) to a user program. Until now it uses the HIDIOCGDEVINFO ioctl call, because I don't know better :-(. Perhaps, it will be ok for you - and I will be happy, if you assign 8 minor numbers. I have tested it in several environments and it works very well for me. However, it has a problem with two or more devices at the same hub, if the two or more devices need 1 ms interrupt-in transfers. Unfortunately more than one interrupt-in transfer every ms isn't possible (ehci driver?). This is why the min_interrupt_in_interval and min_interrupt_out_interval are increased to 2 ms (see the corresponding module parameters). This way, I can use two devices simultaneously at the same hub. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ldusb.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 806 insertions(+) create mode 100644 drivers/usb/misc/ldusb.c (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 284f95723ee..df014c2a7c5 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ obj-$(CONFIG_USB_LCD) += misc/ +obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 3a896954b3a..6649531fa82 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -139,6 +139,16 @@ config USB_IDMOUSE source "drivers/usb/misc/sisusbvga/Kconfig" +config USB_LD + tristate "USB LD driver" + depends on USB && EXPERIMENTAL + help + This driver is for generic USB devices that use interrupt transfers, + like LD Didactic's USB devices. + + To compile this driver as a module, choose M here: the + module will be called ldusb. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 4a3814cbd48..862e40a8368 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_LCD) += usblcd.o +obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c new file mode 100644 index 00000000000..66ec88354b9 --- /dev/null +++ b/drivers/usb/misc/ldusb.c @@ -0,0 +1,794 @@ +/** + * Generic USB driver for report based interrupt in/out devices + * like LD Didactic's USB devices. LD Didactic's USB devices are + * HID devices which do not use HID report definitons (they use + * raw interrupt in and our reports only for communication). + * + * This driver uses a ring buffer for time critical reading of + * interrupt in reports and provides read and write methods for + * raw interrupt reports (similar to the Windows HID driver). + * Devices based on the book USB COMPLETE by Jan Axelson may need + * such a compatibility to the Windows HID driver. + * + * Copyright (C) 2005 Michael Hund + * + * 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. + * + * Derived from Lego USB Tower driver + * Copyright (C) 2003 David Glance + * 2001-2004 Juergen Stuber + * + * V0.1 (mh) Initial version + * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Define these values to match your devices */ +#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */ +#define USB_DEVICE_ID_CASSY 0x1000 /* USB Product ID for all CASSY-S modules */ +#define USB_DEVICE_ID_POCKETCASSY 0x1010 /* USB Product ID for Pocket-CASSY */ +#define USB_DEVICE_ID_MOBILECASSY 0x1020 /* USB Product ID for Mobile-CASSY */ +#define USB_DEVICE_ID_JWM 0x1080 /* USB Product ID for Joule and Wattmeter */ +#define USB_DEVICE_ID_DMMP 0x1081 /* USB Product ID for Digital Multimeter P (reserved) */ +#define USB_DEVICE_ID_UMIP 0x1090 /* USB Product ID for UMI P */ +#define USB_DEVICE_ID_VIDEOCOM 0x1200 /* USB Product ID for VideoCom */ +#define USB_DEVICE_ID_COM3LAB 0x2000 /* USB Product ID for COM3LAB */ +#define USB_DEVICE_ID_TELEPORT 0x2010 /* USB Product ID for Terminal Adapter */ +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 /* USB Product ID for Network Analyser */ +#define USB_DEVICE_ID_POWERCONTROL 0x2030 /* USB Product ID for Controlling device for Power Electronics */ + +#define USB_VENDOR_ID_VERNIER 0x08f7 +#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 +#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 +#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 +#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 + + +#ifdef CONFIG_USB_DYNAMIC_MINORS +#define USB_LD_MINOR_BASE 0 +#else +#define USB_LD_MINOR_BASE 176 +#endif + +/* table of devices that work with this driver */ +static struct usb_device_id ld_usb_table [] = { + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ld_usb_table); +MODULE_VERSION("V0.11"); +MODULE_AUTHOR("Michael Hund "); +MODULE_DESCRIPTION("LD USB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("LD USB Devices"); + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug = 0; +#endif + +/* Use our own dbg macro */ +#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) + +/* Module parameters */ +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* All interrupt in transfers are collected in a ring buffer to + * avoid racing conditions and get better performance of the driver. + */ +static int ring_buffer_size = 128; +module_param(ring_buffer_size, int, 0); +MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); + +/* The write_buffer can contain more than one interrupt out transfer. + */ +static int write_buffer_size = 10; +module_param(write_buffer_size, int, 0); +MODULE_PARM_DESC(write_buffer_size, "Write buffer size in reports"); + +/* As of kernel version 2.6.4 ehci-hcd uses an + * "only one interrupt transfer per frame" shortcut + * to simplify the scheduling of periodic transfers. + * This conflicts with our standard 1ms intervals for in and out URBs. + * We use default intervals of 2ms for in and 2ms for out transfers, + * which should be fast enough. + * Increase the interval to allow more devices that do interrupt transfers, + * or set to 1 to use the standard interval from the endpoint descriptors. + */ +static int min_interrupt_in_interval = 2; +module_param(min_interrupt_in_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms"); + +static int min_interrupt_out_interval = 2; +module_param(min_interrupt_out_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms"); + +/* Structure to hold all of our device specific stuff */ +struct ld_usb { + struct semaphore sem; /* locks this structure */ + struct usb_interface* intf; /* save off the usb interface pointer */ + + int open_count; /* number of times this port has been opened */ + + char* ring_buffer; + unsigned int ring_head; + unsigned int ring_tail; + + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + + char* interrupt_in_buffer; + struct usb_endpoint_descriptor* interrupt_in_endpoint; + struct urb* interrupt_in_urb; + int interrupt_in_interval; + size_t interrupt_in_endpoint_size; + int interrupt_in_running; + int interrupt_in_done; + + char* interrupt_out_buffer; + struct usb_endpoint_descriptor* interrupt_out_endpoint; + struct urb* interrupt_out_urb; + int interrupt_out_interval; + size_t interrupt_out_endpoint_size; + int interrupt_out_busy; +}; + +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +static struct usb_driver ld_usb_driver; + +/** + * ld_usb_abort_transfers + * aborts transfers and frees associated data structures + */ +static void ld_usb_abort_transfers(struct ld_usb *dev) +{ + /* shutdown transfer */ + if (dev->interrupt_in_running) { + dev->interrupt_in_running = 0; + if (dev->intf) + usb_kill_urb(dev->interrupt_in_urb); + } + if (dev->interrupt_out_busy) + if (dev->intf) + usb_kill_urb(dev->interrupt_out_urb); +} + +/** + * ld_usb_delete + */ +static void ld_usb_delete(struct ld_usb *dev) +{ + ld_usb_abort_transfers(dev); + + /* free data structures */ + usb_free_urb(dev->interrupt_in_urb); + usb_free_urb(dev->interrupt_out_urb); + kfree(dev->ring_buffer); + kfree(dev->interrupt_in_buffer); + kfree(dev->interrupt_out_buffer); + kfree(dev); +} + +/** + * ld_usb_interrupt_in_callback + */ +static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + size_t *actual_buffer; + unsigned int next_ring_head; + int retval; + + if (urb->status) { + if (urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN) { + goto exit; + } else { + dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", + __FUNCTION__, urb->status); + goto resubmit; /* maybe we can recover */ + } + } + + if (urb->actual_length > 0) { + next_ring_head = (dev->ring_head+1) % ring_buffer_size; + if (next_ring_head != dev->ring_tail) { + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_head*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + /* actual_buffer gets urb->actual_length + interrupt_in_buffer */ + *actual_buffer = urb->actual_length; + memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length); + dev->ring_head = next_ring_head; + dbg_info(&dev->intf->dev, "%s: received %d bytes\n", + __FUNCTION__, urb->actual_length); + } else + dev_warn(&dev->intf->dev, + "Ring buffer overflow, %d bytes dropped\n", + urb->actual_length); + } + +resubmit: + /* resubmit if we're still running */ + if (dev->interrupt_in_running && dev->intf) { + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) + dev_err(&dev->intf->dev, + "usb_submit_urb failed (%d)\n", retval); + } + +exit: + dev->interrupt_in_done = 1; + wake_up_interruptible(&dev->read_wait); +} + +/** + * ld_usb_interrupt_out_callback + */ +static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dbg_info(&dev->intf->dev, + "%s - nonzero write interrupt status received: %d\n", + __FUNCTION__, urb->status); + + dev->interrupt_out_busy = 0; + wake_up_interruptible(&dev->write_wait); +} + +/** + * ld_usb_open + */ +static int ld_usb_open(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int subminor; + int retval = 0; + struct usb_interface *interface; + + nonseekable_open(inode, file); + subminor = iminor(inode); + + down(&disconnect_sem); + + interface = usb_find_interface(&ld_usb_driver, subminor); + + if (!interface) { + err("%s - error, can't find device for minor %d\n", + __FUNCTION__, subminor); + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + dev = usb_get_intfdata(interface); + + if (!dev) { + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + /* lock this device */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto unlock_disconnect_exit; + } + + /* allow opening only once */ + if (dev->open_count) { + retval = -EBUSY; + goto unlock_exit; + } + dev->open_count = 1; + + /* initialize in direction */ + dev->ring_head = 0; + dev->ring_tail = 0; + usb_fill_int_urb(dev->interrupt_in_urb, + interface_to_usbdev(interface), + usb_rcvintpipe(interface_to_usbdev(interface), + dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + dev->interrupt_in_endpoint_size, + ld_usb_interrupt_in_callback, + dev, + dev->interrupt_in_interval); + + dev->interrupt_in_running = 1; + dev->interrupt_in_done = 0; + + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + if (retval) { + dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval); + dev->interrupt_in_running = 0; + dev->open_count = 0; + goto unlock_exit; + } + + /* save device in the file's private structure */ + file->private_data = dev; + +unlock_exit: + up(&dev->sem); + +unlock_disconnect_exit: + up(&disconnect_sem); + + return retval; +} + +/** + * ld_usb_release + */ +static int ld_usb_release(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int retval = 0; + + dev = file->private_data; + + if (dev == NULL) { + retval = -ENODEV; + goto exit; + } + + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + if (dev->open_count != 1) { + retval = -ENODEV; + goto unlock_exit; + } + if (dev->intf == NULL) { + /* the device was unplugged before the file was released */ + up(&dev->sem); + /* unlock here as ld_usb_delete frees dev */ + ld_usb_delete(dev); + goto exit; + } + + /* wait until write transfer is finished */ + if (dev->interrupt_out_busy) + wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); + ld_usb_abort_transfers(dev); + dev->open_count = 0; + +unlock_exit: + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_poll + */ +static unsigned int ld_usb_poll(struct file *file, poll_table *wait) +{ + struct ld_usb *dev; + unsigned int mask = 0; + + dev = file->private_data; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + if (dev->ring_head != dev->ring_tail) + mask |= POLLIN | POLLRDNORM; + if (!dev->interrupt_out_busy) + mask |= POLLOUT | POLLWRNORM; + + return mask; +} + +/** + * ld_usb_read + */ +static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct ld_usb *dev; + size_t *actual_buffer; + size_t bytes_to_read; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to read */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait for data */ + if (dev->ring_head == dev->ring_tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); + if (retval < 0) + goto unlock_exit; + } + + /* actual_buffer contains actual_length + interrupt_in_buffer */ + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + bytes_to_read = min(count, *actual_buffer); + if (bytes_to_read < *actual_buffer) + dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n", + *actual_buffer-bytes_to_read); + + /* copy one interrupt_in_buffer from ring_buffer into userspace */ + if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) { + retval = -EFAULT; + goto unlock_exit; + } + dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; + + retval = bytes_to_read; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_write + */ +static ssize_t ld_usb_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct ld_usb *dev; + size_t bytes_to_write; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to write */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait until previous transfer is finished */ + if (dev->interrupt_out_busy) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy); + if (retval < 0) { + goto unlock_exit; + } + } + + /* write the data into interrupt_out_buffer from userspace */ + bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); + if (bytes_to_write < count) + dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write); + dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write); + + if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { + retval = -EFAULT; + goto unlock_exit; + } + + if (dev->interrupt_out_endpoint == NULL) { + /* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */ + retval = usb_control_msg(interface_to_usbdev(dev->intf), + usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0), + 9, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 1 << 8, 0, + dev->interrupt_out_buffer, + bytes_to_write, + USB_CTRL_SET_TIMEOUT * HZ); + if (retval < 0) + err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); + goto unlock_exit; + } + + /* send off the urb */ + usb_fill_int_urb(dev->interrupt_out_urb, + interface_to_usbdev(dev->intf), + usb_sndintpipe(interface_to_usbdev(dev->intf), + dev->interrupt_out_endpoint->bEndpointAddress), + dev->interrupt_out_buffer, + bytes_to_write, + ld_usb_interrupt_out_callback, + dev, + dev->interrupt_out_interval); + + dev->interrupt_out_busy = 1; + wmb(); + + retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); + if (retval) { + dev->interrupt_out_busy = 0; + err("Couldn't submit interrupt_out_urb %d\n", retval); + goto unlock_exit; + } + retval = bytes_to_write; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/* file operations needed when we register this driver */ +static struct file_operations ld_usb_fops = { + .owner = THIS_MODULE, + .read = ld_usb_read, + .write = ld_usb_write, + .open = ld_usb_open, + .release = ld_usb_release, + .poll = ld_usb_poll, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver ld_usb_class = { + .name = "ldusb%d", + .fops = &ld_usb_fops, + .minor_base = USB_LD_MINOR_BASE, +}; + +/** + * ld_usb_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ld_usb *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + char *buffer; + int i; + int retval = -ENOMEM; + + /* allocate memory for our device state and intialize it */ + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&intf->dev, "Out of memory\n"); + goto exit; + } + memset(dev, 0x00, sizeof(*dev)); + init_MUTEX(&dev->sem); + dev->intf = intf; + init_waitqueue_head(&dev->read_wait); + init_waitqueue_head(&dev->write_wait); + + /* workaround for early firmware versions on fast computers */ + if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) && + ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) || + (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) && + (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { + buffer = kmalloc(256, GFP_KERNEL); + /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ + usb_string(udev, 255, buffer, 256); + kfree(buffer); + } + + iface_desc = intf->cur_altsetting; + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_in_endpoint = endpoint; + } + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_out_endpoint = endpoint; + } + } + if (dev->interrupt_in_endpoint == NULL) { + dev_err(&intf->dev, "Interrupt in endpoint not found\n"); + goto error; + } + if (dev->interrupt_out_endpoint == NULL) + dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); + + dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); + dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); + if (!dev->ring_buffer) { + dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); + goto error; + } + dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_in_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); + goto error; + } + dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_in_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); + goto error; + } + dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : + udev->descriptor.bMaxPacketSize0; + dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_out_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); + goto error; + } + dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_out_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); + goto error; + } + dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + if (dev->interrupt_out_endpoint) + dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(intf, dev); + + retval = usb_register_dev(intf, &ld_usb_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&intf->dev, "Not able to get a minor for this device.\n"); + usb_set_intfdata(intf, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ + dev_info(&intf->dev, "LD USB Device #%d now attached to major %d minor %d\n", + (intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor); + +exit: + return retval; + +error: + ld_usb_delete(dev); + + return retval; +} + +/** + * ld_usb_disconnect + * + * Called by the usb core when the device is removed from the system. + */ +static void ld_usb_disconnect(struct usb_interface *intf) +{ + struct ld_usb *dev; + int minor; + + down(&disconnect_sem); + + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + down(&dev->sem); + + minor = intf->minor; + + /* give back our minor */ + usb_deregister_dev(intf, &ld_usb_class); + + /* if the device is not opened, then we clean up right now */ + if (!dev->open_count) { + up(&dev->sem); + ld_usb_delete(dev); + } else { + dev->intf = NULL; + up(&dev->sem); + } + + up(&disconnect_sem); + + dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", + (minor - USB_LD_MINOR_BASE)); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver ld_usb_driver = { + .owner = THIS_MODULE, + .name = "ldusb", + .probe = ld_usb_probe, + .disconnect = ld_usb_disconnect, + .id_table = ld_usb_table, +}; + +/** + * ld_usb_init + */ +static int __init ld_usb_init(void) +{ + int retval; + + /* register this driver with the USB subsystem */ + retval = usb_register(&ld_usb_driver); + if (retval) + err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval); + + return retval; +} + +/** + * ld_usb_exit + */ +static void __exit ld_usb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&ld_usb_driver); +} + +module_init(ld_usb_init); +module_exit(ld_usb_exit); + -- cgit v1.2.3 From ab611487d8ada506e511d2b8f22fb8e7be9939b9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 12 Jul 2005 12:08:43 -0700 Subject: [NET]: __be'ify *_type_trans() tr_type_trans(), hippi_type_trans() left as-is. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/myri_sbus.c | 2 +- drivers/net/plip.c | 2 +- drivers/net/wan/farsync.c | 3 +-- drivers/net/wan/hdlc_cisco.c | 3 +-- drivers/net/wan/hdlc_ppp.c | 3 +-- drivers/net/wan/hdlc_raw.c | 3 +-- drivers/s390/net/qeth_main.c | 2 +- 7 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index aad5494c83c..f0996ce5c26 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -369,7 +369,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. */ -static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index f4b62405d2e..21537ee3a6a 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -540,7 +540,7 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev, * in far too many old systems not all even running Linux. */ -static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 7217d44e885..2c83cca34b8 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -861,8 +861,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, /* * Mark it for our own raw sockets interface */ -static unsigned short farsync_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev) { skb->dev = dev; skb->mac.raw = skb->data; diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 87496843681..48c03c11cd9 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -91,8 +91,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, -static unsigned short cisco_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) { hdlc_header *data = (hdlc_header*)skb->data; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 7cd6195a2e4..b81263eaede 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -66,8 +66,7 @@ static void ppp_close(struct net_device *dev) -static unsigned short ppp_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_WAN_PPP); } diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index c41fb70b692..9456d31cb1c 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -24,8 +24,7 @@ #include -static unsigned short raw_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_IP); } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 3cb88c77003..8f4d2999af8 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2210,7 +2210,7 @@ no_mem: return NULL; } -static inline unsigned short +static inline __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; -- cgit v1.2.3 From 4645df1035b34be2d431d6a10b08e1c06bcd3361 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 12 Jul 2005 13:58:08 -0700 Subject: [PATCH] aacraid: swapped kmalloc args. Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aacraid/commctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 1fef92d55de..390cd67c57c 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -469,7 +469,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } - user_srbcmd = kmalloc(GFP_KERNEL, fibsize); + user_srbcmd = kmalloc(fibsize, GFP_KERNEL); if (!user_srbcmd) { dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n")); rcode = -ENOMEM; -- cgit v1.2.3 From 70d1d47c47c4643af357cb44d0d891c1b765f2ab Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Tue, 12 Jul 2005 13:58:09 -0700 Subject: [PATCH] quiet ide-cd warning This shuts up a potential uninitialized variable warning. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-cd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0a31cfda08a..74af7e07486 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -431,7 +431,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive, #if VERBOSE_IDE_CD_ERRORS { int i; - const char *s; + const char *s = "bad sense key!"; char buf[80]; printk ("ATAPI device %s:\n", drive->name); @@ -446,8 +446,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive, if (sense->sense_key < ARY_LEN(sense_key_texts)) s = sense_key_texts[sense->sense_key]; - else - s = "bad sense key!"; printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); -- cgit v1.2.3 From 862104e56329babf0b9571281e9516fe6259dd17 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:15 -0700 Subject: [PATCH] yenta: fix parent resource determination If the CardBus windows were pre-configured and the CardBus bridge is behind a transparent PCI-PCI bridge, pci_find_parent_resource() might return a different resource than the real parent if it is called before the window is determined. Therefore, move that call around. Also fix return of value in void function. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 0e7aa817669..5e0a9980d2f 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -551,7 +551,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; /* Already allocated? */ if (res->parent) - return 0; + return; /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ mask = ~0xfff; @@ -562,25 +562,23 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ bus = socket->dev->subordinate; res->name = bus->name; res->flags = type; - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - - if (!root) - return; start = config_readl(socket, offset) & mask; end = config_readl(socket, offset+4) | ~mask; if (start && end > start && !override_bios) { res->start = start; res->end = end; - if (request_resource(root, res) == 0) + root = pci_find_parent_resource(socket->dev, res); + if (root && (request_resource(root, res) == 0)) return; - printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", + printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n", pci_name(socket->dev), nr); - res->start = res->end = 0; } + res->start = 0; + res->end = 0; + root = pci_find_parent_resource(socket->dev, res); + if (type & IORESOURCE_IO) { align = 1024; size = BRIDGE_IO_MAX; @@ -629,7 +627,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket) yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); yenta_allocate_res(socket, 1, IORESOURCE_MEM); yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ + yenta_allocate_res(socket, 3, IORESOURCE_IO); } -- cgit v1.2.3 From 278798357d4a8658067dc9ac399d8ffba8389f03 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:16 -0700 Subject: [PATCH] yenta: same resources in same structs drivers/pci/setup-bus.c enumerates the CardBus windows (bus->resources[]) Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 5e0a9980d2f..d3807e22fe0 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -539,13 +539,12 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #endif -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) +static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct pci_bus *bus; struct resource *root, *res; u32 start, end; u32 align, size, min; - unsigned offset; unsigned mask; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; @@ -558,13 +557,12 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ if (type & IORESOURCE_IO) mask = ~3; - offset = 0x1c + 8*nr; bus = socket->dev->subordinate; res->name = bus->name; res->flags = type; - start = config_readl(socket, offset) & mask; - end = config_readl(socket, offset+4) | ~mask; + start = config_readl(socket, addr_start) & mask; + end = config_readl(socket, addr_end) | ~mask; if (start && end > start && !override_bios) { res->start = start; res->end = end; @@ -607,8 +605,8 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ do { if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { - config_writel(socket, offset, res->start); - config_writel(socket, offset+4, res->end); + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); return; } size = size/2; @@ -624,10 +622,14 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ */ static void yenta_allocate_resources(struct yenta_socket *socket) { - yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); - yenta_allocate_res(socket, 1, IORESOURCE_MEM); - yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); + yenta_allocate_res(socket, 0, IORESOURCE_IO, + PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0); + yenta_allocate_res(socket, 1, IORESOURCE_IO, + PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1); + yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, + PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0); + yenta_allocate_res(socket, 3, IORESOURCE_MEM, + PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); } -- cgit v1.2.3 From eb0a90b4970d667e9ae9df538710f12b8e78e442 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:17 -0700 Subject: [PATCH] yenta: allocate resource fixes The current CardBus window allocation code in yenta_socket is unable to handle the transparent PCI-bridge handling update in 2.6.13. We need to check _all_ resources of a given type to find the best one suitable for CardBus windows, not just the first one. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 126 +++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index d3807e22fe0..f9d2367b6bd 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -527,24 +527,87 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) * Use an adaptive allocation for the memory resource, * sometimes the memory behind pci bridges is limited: * 1/8 of the size of the io window of the parent. - * max 4 MB, min 16 kB. + * max 4 MB, min 16 kB. We try very hard to not get below + * the "ACC" values, though. */ #define BRIDGE_MEM_MAX 4*1024*1024 +#define BRIDGE_MEM_ACC 128*1024 #define BRIDGE_MEM_MIN 16*1024 -#define BRIDGE_IO_MAX 256 +#define BRIDGE_IO_MAX 512 +#define BRIDGE_IO_ACC 256 #define BRIDGE_IO_MIN 32 #ifndef PCIBIOS_MIN_CARDBUS_IO #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #endif +static int yenta_search_one_res(struct resource *root, struct resource *res, + u32 min) +{ + u32 align, size, start, end; + + if (res->flags & IORESOURCE_IO) { + align = 1024; + size = BRIDGE_IO_MAX; + start = PCIBIOS_MIN_CARDBUS_IO; + end = ~0U; + } else { + unsigned long avail = root->end - root->start; + int i; + size = BRIDGE_MEM_MAX; + if (size > avail/8) { + size=(avail+1)/8; + /* round size down to next power of 2 */ + i = 0; + while ((size /= 2) != 0) + i++; + size = 1 << i; + } + if (size < min) + size = min; + align = size; + start = PCIBIOS_MIN_MEM; + end = ~0U; + } + + do { + if (allocate_resource(root, res, size, start, end, align, + NULL, NULL)==0) { + return 1; + } + size = size/2; + align = size; + } while (size >= min); + + return 0; +} + + +static int yenta_search_res(struct yenta_socket *socket, struct resource *res, + u32 min) +{ + int i; + for (i=0; idev->bus->resource[i]; + if (!root) + continue; + + if ((res->flags ^ root->flags) & + (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH)) + continue; /* Wrong type */ + + if (yenta_search_one_res(root, res, min)) + return 1; + } + return 0; +} + static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct pci_bus *bus; struct resource *root, *res; u32 start, end; - u32 align, size, min; unsigned mask; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; @@ -573,48 +636,35 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ pci_name(socket->dev), nr); } - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - if (type & IORESOURCE_IO) { - align = 1024; - size = BRIDGE_IO_MAX; - min = BRIDGE_IO_MIN; - start = PCIBIOS_MIN_CARDBUS_IO; - end = ~0U; + if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || + (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || + (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } } else { - unsigned long avail = root->end - root->start; - int i; - size = BRIDGE_MEM_MAX; - if (size > avail/8) { - size=(avail+1)/8; - /* round size down to next power of 2 */ - i = 0; - while ((size /= 2) != 0) - i++; - size = 1 << i; + if (type & IORESOURCE_PREFETCH) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } + /* Approximating prefetchable by non-prefetchable */ + res->flags = IORESOURCE_MEM; } - if (size < BRIDGE_MEM_MIN) - size = BRIDGE_MEM_MIN; - min = BRIDGE_MEM_MIN; - align = size; - start = PCIBIOS_MIN_MEM; - end = ~0U; - } - - do { - if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { config_writel(socket, addr_start, res->start); config_writel(socket, addr_end, res->end); - return; } - size = size/2; - align = size; - } while (size >= min); + } + printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", - pci_name(socket->dev), type); - res->start = res->end = 0; + pci_name(socket->dev), type); + res->start = res->end = res->flags = 0; } /* -- cgit v1.2.3 From 01e77d31d11a767c9da665f46e075756aef4fc4f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 12 Jul 2005 13:58:32 -0700 Subject: [PATCH] IBM_ASM Kconfig corrections This patch contains the following fixes: - IBM_ASM must depend on PCI - remove useless "default n" - correct the URL to further information Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4cecdafeb87..7fc692a8f5b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -6,8 +6,7 @@ menu "Misc devices" config IBM_ASM tristate "Device driver for IBM RSA service processor" - depends on X86 && EXPERIMENTAL - default n + depends on X86 && PCI && EXPERIMENTAL ---help--- This option enables device driver support for in-band access to the IBM RSA (Condor) service processor in eServer xSeries systems. @@ -22,7 +21,7 @@ config IBM_ASM WARNING: This software may not be supported or function correctly on your IBM server. Please consult the IBM ServerProven - website for + website for information on the specific driver level and support statement for your IBM server. -- cgit v1.2.3 From 6e498c1080ae794a8dc788152002fb39994ae78b Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 12 Jul 2005 13:58:32 -0700 Subject: [PATCH] TB0219: add PCI IRQ initialization This patch adds PCI IRQ initialization to TB0219 driver. Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tb0219.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 5413f290885..eb7058cbf01 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -24,6 +24,8 @@ #include #include +#include +#include MODULE_AUTHOR("Yoichi Yuasa "); MODULE_DESCRIPTION("TANBAC TB0219 base board driver"); @@ -266,6 +268,21 @@ static void tb0219_restart(char *command) tb0219_write(TB0219_RESET, 0); } +static void tb0219_pci_irq_init(void) +{ + /* PCI Slot 1 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW); + + /* PCI Slot 2 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW); + + /* PCI Slot 3 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); +} + static int tb0219_probe(struct device *dev) { int retval; @@ -292,6 +309,8 @@ static int tb0219_probe(struct device *dev) old_machine_restart = _machine_restart; _machine_restart = tb0219_restart; + tb0219_pci_irq_init(); + if (major == 0) { major = retval; printk(KERN_INFO "TB0219: major number %d\n", major); -- cgit v1.2.3 From 58ba006be9b5a8f14f32c530d19fcd4e633aadf8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 12 Jul 2005 13:58:37 -0700 Subject: [PATCH] dvb: LGDT3302 QAM256 initialization fix - Initialize all non mutually exclusive variables without regard to the mode selected. - Do a software reset each time the parameters are set, regardless of whether anything changes. This may allow an application to recover from a hung condition. - Improved error reporting. - Removed $Id:$ Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 64 ++++++++++++++++------------------ 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index 09c914256e4..2eea03d218c 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -1,6 +1,4 @@ /* - * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $ - * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * * Copyright (C) 2005 Wilson Michaels @@ -83,7 +81,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } } else { u8 tmp[] = { buf[0], buf[1] }; @@ -96,7 +97,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, tmp[1] = buf[i]; if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } tmp[0]++; } @@ -218,6 +222,8 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Change only if we are actually changing the modulation */ if (state->current_modulation != param->u.vsb.modulation) { + int value; + switch(param->u.vsb.modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __FUNCTION__); @@ -266,36 +272,29 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_writebytes(state, state->config->demod_address, demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); - if (param->u.vsb.modulation == VSB_8) { - /* Initialization for VSB modes only */ - /* Change the value of NCOCTFV[25:0]of carrier - recovery center frequency register for VSB */ - i2c_writebytes(state, state->config->demod_address, + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + i2c_writebytes(state, state->config->demod_address, vsb_freq_cfg, sizeof(vsb_freq_cfg)); - } else { - /* Initialization for QAM modes only */ - /* Set the value of 'INLVTHD' register 0x2a/0x2c - to value from 'IFACC' register 0x39/0x3b -1 */ - int value; - i2c_selectreadbytes(state, AGC_RFIF_ACC0, - &agc_delay_cfg[1], 3); - value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; - value = value -1; - dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); - agc_delay_cfg[1] = (value >> 8) & 0x0f; - agc_delay_cfg[2] = 0x00; - agc_delay_cfg[3] = value & 0xff; - i2c_writebytes(state, state->config->demod_address, - agc_delay_cfg, sizeof(agc_delay_cfg)); - - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwith */ - i2c_writebytes(state, state->config->demod_address, - agc_loop_cfg, sizeof(agc_loop_cfg)); - } + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to value from 'IFACC' register 0x39/0x3b -1 */ + i2c_selectreadbytes(state, AGC_RFIF_ACC0, + &agc_delay_cfg[1], 3); + value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; + value = value -1; + dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); + agc_delay_cfg[1] = (value >> 8) & 0x0f; + agc_delay_cfg[2] = 0x00; + agc_delay_cfg[3] = value & 0xff; + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); state->config->set_ts_params(fe, 0); - lgdt3302_SwReset(state); state->current_modulation = param->u.vsb.modulation; } @@ -311,11 +310,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_readbytes(state, state->config->pll_address, buf, 1); dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); - lgdt3302_SwReset(state); - /* Update current frequency */ state->current_frequency = param->frequency; } + lgdt3302_SwReset(state); return 0; } -- cgit v1.2.3 From 8df3d46077e63ab87f954eb6e827689cdfe97155 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 12 Jul 2005 13:58:38 -0700 Subject: [PATCH] dvb: usb: fix some typos corrected some typos. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 2 +- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 6 +++--- drivers/media/dvb/dvb-usb/vp7045.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index bdd72f77970..3491ff40885 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -175,7 +175,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) int dvb_usb_fe_init(struct dvb_usb_device* d) { if (d->props.frontend_attach == NULL) { - err("strange '%s' don't want to attach a frontend.",d->desc->name); + err("strange '%s' doesn't want to attach a frontend.",d->desc->name); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index c3b3ae4f3ec..65f0c095abc 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -51,17 +51,17 @@ static int dvb_usb_init(struct dvb_usb_device *d) /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a HW PID filter)"); + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); return -ENODEV; } if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) || (d->props.caps & DVB_USB_NEED_PID_FILTERING)) { - info("will use the device's hw PID filter."); + info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count); d->pid_filtering = 1; d->max_feed_count = d->props.pid_filter_count; } else { - info("will pass the complete MPEG2 transport stream to the demuxer."); + info("will pass the complete MPEG2 transport stream to the software demuxer."); d->pid_filtering = 0; d->max_feed_count = 255; } diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5adc5d69ec8..9ac95f54f9f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -128,7 +128,7 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x0f, KEY_TEXT } /* Teletext */ }; -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) +static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key; int i; @@ -144,7 +144,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; - *key_buf = vp7045_rc_keys[i].event; + *event = vp7045_rc_keys[i].event; break; } return 0; -- cgit v1.2.3 From 27b05fd22f8a1f9afd0377817b1811cfc95f8b7b Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Tue, 12 Jul 2005 13:58:39 -0700 Subject: [PATCH] dvb: fix kobject names (no slashes) The / in the driver name (budget dvb /w video in) is not a valid character for device names - removed it, now it works! Same for ttusb-budget. Signed-off-by: Patrick Boettcher Signed-off-by: Julian Scheel Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b65f4b0a481..9746d2bb916 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1022,7 +1022,7 @@ static struct pci_device_id pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { - .name = "budget dvb /w video in\0", + .name = "budget_av", .pci_tbl = pci_tbl, .module = THIS_MODULE, diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 2c17a5f5834..aa43b5fcb8e 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1626,7 +1626,7 @@ static struct usb_device_id ttusb_table[] = { MODULE_DEVICE_TABLE(usb, ttusb_table); static struct usb_driver ttusb_driver = { - .name = "Technotrend/Hauppauge USB-Nova", + .name = "ttusb", .probe = ttusb_probe, .disconnect = ttusb_disconnect, .id_table = ttusb_table, -- cgit v1.2.3 From a6dfa37888298e8369f197883ae5f058fbd98a70 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Tue, 12 Jul 2005 13:58:40 -0700 Subject: [PATCH] dvb: dst: printk -> dprintk - stop log spamming when running femon (printk -> dprintk) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 9bd12832e3d..07a0b0a968a 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -928,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__); + dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; -- cgit v1.2.3 From de9c634270df3e27675a3c0e95545d2b3f754e3f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:41 -0700 Subject: [PATCH] v4l: BTTV input Changes to comply with CodingStyle: // comments converted to /* */ Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/ir-kbd-i2c.c | 51 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 92664f75d32..9fc5055e001 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -1,5 +1,5 @@ /* - * $Id: ir-kbd-i2c.c,v 1.10 2004/12/09 12:51:35 kraxel Exp $ + * $Id: ir-kbd-i2c.c,v 1.11 2005/07/07 16:42:11 mchehab Exp $ * * keyboard input driver for i2c IR remote controls * @@ -66,26 +66,26 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = { [ 29 ] = KEY_PAGEDOWN, [ 19 ] = KEY_SOUND, - [ 24 ] = KEY_KPPLUSMINUS, // CH +/- - [ 22 ] = KEY_SUBTITLE, // CC - [ 13 ] = KEY_TEXT, // TTX - [ 11 ] = KEY_TV, // AIR/CBL - [ 17 ] = KEY_PC, // PC/TV - [ 23 ] = KEY_OK, // CH RTN - [ 25 ] = KEY_MODE, // FUNC - [ 12 ] = KEY_SEARCH, // AUTOSCAN + [ 24 ] = KEY_KPPLUSMINUS, /* CH +/- */ + [ 22 ] = KEY_SUBTITLE, /* CC */ + [ 13 ] = KEY_TEXT, /* TTX */ + [ 11 ] = KEY_TV, /* AIR/CBL */ + [ 17 ] = KEY_PC, /* PC/TV */ + [ 23 ] = KEY_OK, /* CH RTN */ + [ 25 ] = KEY_MODE, /* FUNC */ + [ 12 ] = KEY_SEARCH, /* AUTOSCAN */ /* Not sure what to do with these ones! */ - [ 15 ] = KEY_SELECT, // SOURCE - [ 10 ] = KEY_KPPLUS, // +100 - [ 20 ] = KEY_KPEQUAL, // SYNC - [ 28 ] = KEY_MEDIA, // PC/TV + [ 15 ] = KEY_SELECT, /* SOURCE */ + [ 10 ] = KEY_KPPLUS, /* +100 */ + [ 20 ] = KEY_KPEQUAL, /* SYNC */ + [ 28 ] = KEY_MEDIA, /* PC/TV */ }; static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0x3 ] = KEY_POWER, [ 0x6f ] = KEY_MUTE, - [ 0x10 ] = KEY_BACKSPACE, // Recall + [ 0x10 ] = KEY_BACKSPACE, /* Recall */ [ 0x11 ] = KEY_KP0, [ 0x4 ] = KEY_KP1, @@ -97,7 +97,7 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0xc ] = KEY_KP7, [ 0xd ] = KEY_KP8, [ 0xe ] = KEY_KP9, - [ 0x12 ] = KEY_KPDOT, // 100+ + [ 0x12 ] = KEY_KPDOT, /* 100+ */ [ 0x7 ] = KEY_VOLUMEUP, [ 0xb ] = KEY_VOLUMEDOWN, @@ -109,25 +109,16 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0x13 ] = KEY_CHANNELDOWN, [ 0x48 ] = KEY_ZOOM, - [ 0x1b ] = KEY_VIDEO, // Video source -#if 0 - [ 0x1f ] = KEY_S, // Snapshot -#endif - [ 0x49 ] = KEY_LANGUAGE, // MTS Select - [ 0x19 ] = KEY_SEARCH, // Auto Scan + [ 0x1b ] = KEY_VIDEO, /* Video source */ + [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */ + [ 0x19 ] = KEY_SEARCH, /* Auto Scan */ [ 0x4b ] = KEY_RECORD, [ 0x46 ] = KEY_PLAY, - [ 0x45 ] = KEY_PAUSE, // Pause + [ 0x45 ] = KEY_PAUSE, /* Pause */ [ 0x44 ] = KEY_STOP, -#if 0 - [ 0x43 ] = KEY_T, // Time Shift - [ 0x47 ] = KEY_Y, // Time Shift OFF - [ 0x4a ] = KEY_O, // TOP - [ 0x17 ] = KEY_F, // SURF CH -#endif - [ 0x40 ] = KEY_FORWARD, // Forward ? - [ 0x42 ] = KEY_REWIND, // Backward ? + [ 0x40 ] = KEY_FORWARD, /* Forward ? */ + [ 0x42 ] = KEY_REWIND, /* Backward ? */ }; -- cgit v1.2.3 From fa9846a8c5965636fbade8655ae0ce1f9a655bd4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:42 -0700 Subject: [PATCH] v4l: BTTV update - use DMA_32BIT_MASK. - Rename tuner structures fields. - Tail spaces removed. - I2C cleanups and converged to a basic reference structure. - Removed unused structures. - Removed BTTV version check. Signed-off-by: Signed-off-by: Michael Krufky Signed-Off-By: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bttv-cards.c | 110 +++++--------------------------------- drivers/media/video/bttv-driver.c | 19 ++----- drivers/media/video/bttv-i2c.c | 26 ++++++--- drivers/media/video/bttv-risc.c | 9 ---- 4 files changed, 35 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 251092e7f19..2dbf5ec43ab 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1,5 +1,5 @@ /* - $Id: bttv-cards.c,v 1.49 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-cards.c,v 1.53 2005/07/05 17:37:35 nsh Exp $ bttv-cards.c @@ -39,9 +39,6 @@ #include #include "bttvp.h" -#if 0 /* not working yet */ -#include "bt832.h" -#endif /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -513,13 +510,8 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0x01fe00, .muxsel = { 2, 3, 1, 1}, -#if 0 - // old - .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }, -#else // 2003-10-20 by "Anton A. Arapov" .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, -#endif .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, @@ -766,14 +758,9 @@ struct tvcard bttv_tvcards[] = { .tuner = 0, .svhs = 2, .muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector -#if 0 - .gpiomask = 0xc33000, - .audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 }, -#else /* Alexander Varakin [stereo version] */ .gpiomask = 0xb33000, .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 }, -#endif /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) gpio23 -- hef4052:nEnable (0x800000) gpio12 -- hef4052:A1 @@ -1603,20 +1590,11 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 4, .audio_inputs = 1, .tuner = -1, -#if 0 /* TODO ... */ - .svhs = OSPREY540_SVID_ANALOG, - .muxsel = { [OSPREY540_COMP_ANALOG] = 2, - [OSPREY540_SVID_ANALOG] = 3, }, -#endif .pll = PLL_28, .tuner_type = -1, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, -#if 0 /* TODO ... */ - .muxsel_hook = osprey_540_muxsel, - .picture_hook = osprey_540_set_picture, -#endif },{ /* ---- card 0x5C ---------------------------------- */ @@ -2546,21 +2524,12 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input) btaor((2)<<5, ~(3<<5), BT848_IFORM); gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); -#if 0 - /* svhs */ - /* wake chroma ADC */ - btand(~BT848_ADC_C_SLEEP, BT848_ADC); - /* set to YC video */ - btor(BT848_CONTROL_COMP, BT848_E_CONTROL); - btor(BT848_CONTROL_COMP, BT848_O_CONTROL); -#else /* composite */ /* set chroma ADC to sleep */ btor(BT848_ADC_C_SLEEP, BT848_ADC); /* set to composite video */ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); -#endif /* switch sync drive off */ gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); @@ -2813,10 +2782,18 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->tuner_type = tuner[btv->c.nr]; printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); if (btv->pinnacle_id != UNSET) - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); - if (btv->tuner_type != UNSET) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (btv->tuner_type != UNSET) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = ADDR_UNSET; + + bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); + } + btv->svhs = bttv_tvcards[btv->c.type].svhs; if (svhs[btv->c.nr] != UNSET) btv->svhs = svhs[btv->c.nr]; @@ -3125,14 +3102,6 @@ static int tuner_0_table[] = { TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, TUNER_PHILIPS_FM1216ME_MK3 }; -#if 0 -int tuner_0_fm_table[] = { - PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL, - PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, - PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, - PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, - PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL}; -#endif static int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, @@ -3218,36 +3187,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) static void __devinit boot_bt832(struct bttv *btv) { -#if 0 /* not working yet */ - int resetbit=0; - - switch (btv->c.type) { - case BTTV_PXELVWPLTVPAK: - resetbit = 0x400000; - break; - case BTTV_MODTEC_205: - resetbit = 1<<9; - break; - default: - BUG(); - } - - request_module("bt832"); - bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL); - - printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->c.nr,resetbit); - gpio_write(0); - gpio_inout(resetbit, resetbit); - udelay(5); - gpio_bits(resetbit, resetbit); - udelay(5); - gpio_bits(resetbit, 0); - udelay(5); - - // bt832 on pixelview changes from i2c 0x8a to 0x88 after - // being reset as above. So we must follow by this: - bttv_call_i2c_clients(btv, BT832_REATTACH, NULL); -#endif } /* ----------------------------------------------------------------------- */ @@ -3572,11 +3511,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) { dprintk("tea5757_set_freq %d\n",freq); tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ -#if 0 - /* breaks Miro PCTV */ - value = tea5757_read(btv); - dprintk("bttv%d: tea5757 readback=0x%x\n",btv->c.nr,value); -#endif } @@ -3656,13 +3590,8 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val, con; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif val = gpio_read(); if (set) { @@ -3851,13 +3780,8 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif if (set) { if (v->mode & VIDEO_SOUND_MONO) { @@ -3888,13 +3812,8 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0xffff; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif if (set) { if (v->mode & VIDEO_SOUND_MONO) { val = 0x0000; @@ -4371,11 +4290,6 @@ void __devinit bttv_check_chipset(void) latency = 0x0A; #endif -#if 0 - /* print which chipset we have */ - while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev))) - printk(KERN_INFO "bttv: Host bridge is %s\n",pci_name(dev)); -#endif /* print warnings about any quirks found */ if (triton1) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 7d62b394c50..51a0f6d68e7 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,5 @@ /* - $Id: bttv-driver.c,v 1.40 2005/06/16 21:38:45 nsh Exp $ + $Id: bttv-driver.c,v 1.42 2005/07/05 17:37:35 nsh Exp $ bttv - Bt848 frame grabber driver @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -698,12 +699,10 @@ int locked_btres(struct bttv *btv, int bit) static void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits) { -#if 1 /* DEBUG */ if ((fh->resources & bits) != bits) { /* trying to free ressources not allocated by us ... */ printk("bttv: BUG! (btres)\n"); } -#endif down(&btv->reslock); fh->resources &= ~bits; btv->resources &= ~bits; @@ -943,11 +942,6 @@ audio_mux(struct bttv *btv, int mode) i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio; if (btv->opt_automute && !signal && !btv->radio_user) mux = AUDIO_OFF; -#if 0 - printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", - btv->c.nr, mode, btv->audio, signal ? "yes" : "no", - mux, i2c_mux, in_interrupt() ? "yes" : "no"); -#endif val = bttv_tvcards[btv->c.type].audiomux[mux]; gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val); @@ -994,11 +988,6 @@ set_tvnorm(struct bttv *btv, unsigned int norm) case BTTV_VOODOOTV_FM: bttv_tda9880_setnorm(btv,norm); break; -#if 0 - case BTTV_OSPREY540: - osprey_540_set_norm(btv,norm); - break; -#endif } return 0; } @@ -1849,7 +1838,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) if (unlikely(f->tuner != 0)) return -EINVAL; - if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) + if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) return -EINVAL; down(&btv->lock); btv->freq = f->frequency; @@ -3865,7 +3854,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->c.nr); return -EIO; } - if (pci_set_dma_mask(dev, 0xffffffff)) { + if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", btv->c.nr); return -EIO; diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index da448a5f9e9..234a8556376 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -1,5 +1,5 @@ /* - $Id: bttv-i2c.c,v 1.21 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-i2c.c,v 1.25 2005/07/05 17:37:35 nsh Exp $ bttv-i2c.c -- all the i2c code is here @@ -295,14 +295,26 @@ static int attach_inform(struct i2c_client *client) { struct bttv *btv = i2c_get_adapdata(client->adapter); - if (btv->tuner_type != UNSET) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (bttv_debug) + printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n", + btv->c.nr,client->driver->name,client->addr, + i2c_clientname(client)); + if (!client->driver->command) + return 0; + + if (btv->tuner_type != UNSET) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = ADDR_UNSET; + + client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); + } + if (btv->pinnacle_id != UNSET) - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + client->driver->command(client,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); - if (bttv_debug) - printk("bttv%d: i2c attach [client=%s]\n", - btv->c.nr, i2c_clientname(client)); return 0; } diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index bdc5ce6c43b..9ed21fd190c 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -334,10 +334,6 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, } vdelay = tvnorm->vdelay; -#if 0 /* FIXME */ - if (vdelay < btv->vbi.lines*2) - vdelay = btv->vbi.lines*2; -#endif xsf = (width*scaledtwidth)/swidth; geo->hscale = ((totalwidth*4096UL)/xsf-4096); @@ -776,13 +772,8 @@ bttv_overlay_risc(struct bttv *btv, bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); break; case V4L2_FIELD_INTERLACED: -#if 0 - bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0); - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1); -#else bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); -#endif break; default: BUG(); -- cgit v1.2.3 From 41ef7c1ed48cb273c7b7a9ffd48a262a22f84483 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:44 -0700 Subject: [PATCH] v4l: CX88 Update - Removed unused structures. - Removed BTTV version check. - Some debug structs moved to their own .c file and converted to static - Comment changed to express better when attach_inform is running - set_freq removed from set_mode at tuner-core.c. - I2C cleanups and converged to a basic reference structure. - Rename tuner structures fields. - It calls VIDIOC_G_FREQUENCY to get tuner freq from tuner. - added missing contrast offset value, set to 0. - Let Kconfig decide whether to include frontend-specific code. Signed-Off-By: Nickolay V. Shmyrev Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-blackbird.c | 5 - drivers/media/video/cx88/cx88-core.c | 48 +--- drivers/media/video/cx88/cx88-dvb.c | 36 +-- drivers/media/video/cx88/cx88-i2c.c | 31 ++- drivers/media/video/cx88/cx88-input.c | 448 +++++++++++++++--------------- drivers/media/video/cx88/cx88-mpeg.c | 26 +- drivers/media/video/cx88/cx88-reg.h | 11 +- drivers/media/video/cx88/cx88-tvaudio.c | 76 +---- drivers/media/video/cx88/cx88-video.c | 303 +------------------- drivers/media/video/cx88/cx88.h | 12 +- 10 files changed, 296 insertions(+), 700 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 91f8afeded8..4f39688f780 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -690,11 +690,9 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) int bitrate_mode = 1; int bitrate = 7500000; int bitrate_peak = 7500000; -#if 1 bitrate_mode = BLACKBIRD_VIDEO_CBR; bitrate = 4000*1024; bitrate_peak = 4000*1024; -#endif /* assign stream type */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM); @@ -810,9 +808,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */ cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ -#if 0 /* FIXME */ - set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED); -#endif blackbird_codec_settings(dev); msleep(1); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 96cb0ff33bb..5e868f5cd0c 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-core.c,v 1.31 2005/06/22 22:58:04 mchehab Exp $ + * $Id: cx88-core.c,v 1.33 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -470,25 +470,6 @@ int cx88_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -#if 0 /* currently unused, but useful for debugging */ -void cx88_risc_disasm(struct cx88_core *core, - struct btcx_riscmem *risc) -{ - unsigned int i,j,n; - - printk("%s: risc disasm: %p [dma=0x%08lx]\n", - core->name, risc->cpu, (unsigned long)risc->dma); - for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: %04d: ", core->name, i); - n = cx88_risc_decode(risc->cpu[i]); - for (j = 1; j < n; j++) - printk("%s: %04d: 0x%08x [ arg #%d ]\n", - core->name, i+j, risc->cpu[i+j], j); - if (risc->cpu[i] == RISC_JUMP) - break; - } -} -#endif void cx88_sram_channel_dump(struct cx88_core *core, struct sram_channel *ch) @@ -545,30 +526,12 @@ void cx88_sram_channel_dump(struct cx88_core *core, core->name,cx_read(ch->cnt2_reg)); } -/* Used only on cx88-core */ static char *cx88_pci_irqs[32] = { "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err", "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err", "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" }; -/* Used only on cx88-video */ -char *cx88_vid_irqs[32] = { - "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", - "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", - "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", - "y_sync", "u_sync", "v_sync", "vbi_sync", - "opc_err", "par_err", "rip_err", "pci_abort", -}; -/* Used only on cx88-mpeg */ -char *cx88_mpeg_irqs[32] = { - "ts_risci1", NULL, NULL, NULL, - "ts_risci2", NULL, NULL, NULL, - "ts_oflow", NULL, NULL, NULL, - "ts_sync", NULL, NULL, NULL, - "opc_err", "par_err", "rip_err", "pci_abort", - "ts_err?", -}; void cx88_print_irqbits(char *name, char *tag, char **strings, u32 bits, u32 mask) @@ -618,16 +581,11 @@ void cx88_wakeup(struct cx88_core *core, break; buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); -#if 0 - if (buf->count > count) - break; -#else /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; -#endif do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); @@ -955,12 +913,10 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm) norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat); -#if 1 // FIXME: as-is from DScaler dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", norm->cxoformat, cx_read(MO_OUTPUT_FORMAT)); cx_write(MO_OUTPUT_FORMAT, norm->cxoformat); -#endif // MO_SCONV_REG = adc clock / video dec clock * 2^17 tmp64 = adc_clock * (u64)(1 << 17); @@ -1219,8 +1175,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) /* ------------------------------------------------------------------ */ EXPORT_SYMBOL(cx88_print_ioctl); -EXPORT_SYMBOL(cx88_vid_irqs); -EXPORT_SYMBOL(cx88_mpeg_irqs); EXPORT_SYMBOL(cx88_print_irqbits); EXPORT_SYMBOL(cx88_core_irq); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 690477a6791..5544e1d6a34 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.39 2005/07/02 20:00:46 mkrufky Exp $ + * $Id: cx88-dvb.c,v 1.41 2005/07/04 19:35:05 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -30,22 +30,20 @@ #include #include -/* these three frontends need merging via linuxtv cvs ... */ -#define HAVE_CX22702 1 -#define HAVE_OR51132 1 -#define HAVE_LGDT3302 1 - #include "cx88.h" #include "dvb-pll.h" -#include "mt352.h" -#include "mt352_priv.h" -#if HAVE_CX22702 + +#if CONFIG_DVB_MT352 +# include "mt352.h" +# include "mt352_priv.h" +#endif +#if CONFIG_DVB_CX22702 # include "cx22702.h" #endif -#if HAVE_OR51132 +#if CONFIG_DVB_OR51132 # include "or51132.h" #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 # include "lgdt3302.h" #endif @@ -104,6 +102,7 @@ static struct videobuf_queue_ops dvb_qops = { /* ------------------------------------------------------------------ */ +#if CONFIG_DVB_MT352 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; @@ -171,8 +170,9 @@ static struct mt352_config dntv_live_dvbt_config = { .demod_init = dntv_live_dvbt_demod_init, .pll_set = mt352_pll_set, }; +#endif -#if HAVE_CX22702 +#if CONFIG_DVB_CX22702 static struct cx22702_config connexant_refboard_config = { .demod_address = 0x43, .pll_address = 0x60, @@ -186,7 +186,7 @@ static struct cx22702_config hauppauge_novat_config = { }; #endif -#if HAVE_OR51132 +#if CONFIG_DVB_OR51132 static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { @@ -203,7 +203,7 @@ static struct or51132_config pchdtv_hd3000 = { }; #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured) { struct cx8802_dev *dev= fe->dvb->priv; @@ -237,7 +237,7 @@ static int dvb_register(struct cx8802_dev *dev) /* init frontend */ switch (dev->core->board) { -#if HAVE_CX22702 +#if CONFIG_DVB_CX22702 case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config, &dev->core->i2c_adap); @@ -248,6 +248,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); break; #endif +#if CONFIG_DVB_MT352 case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: dev->core->pll_addr = 0x61; dev->core->pll_desc = &dvb_pll_lg_z201; @@ -268,13 +269,14 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, &dev->core->i2c_adap); break; -#if HAVE_OR51132 +#endif +#if CONFIG_DVB_OR51132 case CX88_BOARD_PCHDTV_HD3000: dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, &dev->core->i2c_adap); break; #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: dev->ts_gen_cntrl = 0x08; { diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index b5342234b30..8403c4e9505 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -1,5 +1,5 @@ /* - $Id: cx88-i2c.c,v 1.24 2005/06/17 18:46:23 mkrufky Exp $ + $Id: cx88-i2c.c,v 1.28 2005/07/05 17:37:35 nsh Exp $ cx88-i2c.c -- all the i2c code is here @@ -91,25 +91,32 @@ static int cx8800_bit_getsda(void *data) static int attach_inform(struct i2c_client *client) { - struct tuner_addr tun_addr; + struct tuner_setup tun_setup; struct cx88_core *core = i2c_get_adapdata(client->adapter); - dprintk(1, "i2c attach [addr=0x%x,client=%s]\n", - client->addr, i2c_clientname(client)); + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->name,client->addr,i2c_clientname(client)); if (!client->driver->command) return 0; if (core->radio_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_RADIO; - tun_addr.type = core->radio_type; - tun_addr.addr = core->radio_addr; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->radio_type; + tun_setup.addr = core->radio_addr; + + client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); + } } if (core->tuner_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV; - tun_addr.type = core->tuner_type; - tun_addr.addr = core->tuner_addr; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) { + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->tuner_type; + tun_setup.addr = core->tuner_addr; + + client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); + } } if (core->tda9887_conf) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index bdc26e75ab5..21488779819 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-input.c,v 1.13 2005/06/13 16:07:46 nsh Exp $ + * $Id: cx88-input.c,v 1.15 2005/07/07 13:58:38 mchehab Exp $ * * Device driver for GPIO attached remote control interfaces * on Conexant 2388x based TV/DVB cards. @@ -38,199 +38,206 @@ /* DigitalNow DNTV Live DVB-T Remote */ static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_ESC, // 'go up a level?' - [ 0x01 ] = KEY_KP1, // '1' - [ 0x02 ] = KEY_KP2, // '2' - [ 0x03 ] = KEY_KP3, // '3' - [ 0x04 ] = KEY_KP4, // '4' - [ 0x05 ] = KEY_KP5, // '5' - [ 0x06 ] = KEY_KP6, // '6' - [ 0x07 ] = KEY_KP7, // '7' - [ 0x08 ] = KEY_KP8, // '8' - [ 0x09 ] = KEY_KP9, // '9' - [ 0x0a ] = KEY_KP0, // '0' - [ 0x0b ] = KEY_TUNER, // 'tv/fm' - [ 0x0c ] = KEY_SEARCH, // 'scan' - [ 0x0d ] = KEY_STOP, // 'stop' - [ 0x0e ] = KEY_PAUSE, // 'pause' - [ 0x0f ] = KEY_LIST, // 'source' - - [ 0x10 ] = KEY_MUTE, // 'mute' - [ 0x11 ] = KEY_REWIND, // 'backward <<' - [ 0x12 ] = KEY_POWER, // 'power' - [ 0x13 ] = KEY_S, // 'snap' - [ 0x14 ] = KEY_AUDIO, // 'stereo' - [ 0x15 ] = KEY_CLEAR, // 'reset' - [ 0x16 ] = KEY_PLAY, // 'play' - [ 0x17 ] = KEY_ENTER, // 'enter' - [ 0x18 ] = KEY_ZOOM, // 'full screen' - [ 0x19 ] = KEY_FASTFORWARD, // 'forward >>' - [ 0x1a ] = KEY_CHANNELUP, // 'channel +' - [ 0x1b ] = KEY_VOLUMEUP, // 'volume +' - [ 0x1c ] = KEY_INFO, // 'preview' - [ 0x1d ] = KEY_RECORD, // 'record' - [ 0x1e ] = KEY_CHANNELDOWN, // 'channel -' - [ 0x1f ] = KEY_VOLUMEDOWN, // 'volume -' + [0x00] = KEY_ESC, /* 'go up a level?' */ + /* Keys 0 to 9 */ + [0x0a] = KEY_KP0, + [0x01] = KEY_KP1, + [0x02] = KEY_KP2, + [0x03] = KEY_KP3, + [0x04] = KEY_KP4, + [0x05] = KEY_KP5, + [0x06] = KEY_KP6, + [0x07] = KEY_KP7, + [0x08] = KEY_KP8, + [0x09] = KEY_KP9, + + [0x0b] = KEY_TUNER, /* tv/fm */ + [0x0c] = KEY_SEARCH, /* scan */ + [0x0d] = KEY_STOP, + [0x0e] = KEY_PAUSE, + [0x0f] = KEY_LIST, /* source */ + + [0x10] = KEY_MUTE, + [0x11] = KEY_REWIND, /* backward << */ + [0x12] = KEY_POWER, + [0x13] = KEY_S, /* snap */ + [0x14] = KEY_AUDIO, /* stereo */ + [0x15] = KEY_CLEAR, /* reset */ + [0x16] = KEY_PLAY, + [0x17] = KEY_ENTER, + [0x18] = KEY_ZOOM, /* full screen */ + [0x19] = KEY_FASTFORWARD, /* forward >> */ + [0x1a] = KEY_CHANNELUP, + [0x1b] = KEY_VOLUMEUP, + [0x1c] = KEY_INFO, /* preview */ + [0x1d] = KEY_RECORD, /* record */ + [0x1e] = KEY_CHANNELDOWN, + [0x1f] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ /* IO-DATA BCTV7E Remote */ static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { - [ 0x40 ] = KEY_TV, // TV - [ 0x20 ] = KEY_RADIO, // FM - [ 0x60 ] = KEY_EPG, // EPG - [ 0x00 ] = KEY_POWER, // power - - [ 0x50 ] = KEY_KP1, // 1 - [ 0x30 ] = KEY_KP2, // 2 - [ 0x70 ] = KEY_KP3, // 3 - [ 0x10 ] = KEY_L, // Live - - [ 0x48 ] = KEY_KP4, // 4 - [ 0x28 ] = KEY_KP5, // 5 - [ 0x68 ] = KEY_KP6, // 6 - [ 0x08 ] = KEY_T, // Time Shift - - [ 0x58 ] = KEY_KP7, // 7 - [ 0x38 ] = KEY_KP8, // 8 - [ 0x78 ] = KEY_KP9, // 9 - [ 0x18 ] = KEY_PLAYPAUSE, // Play - - [ 0x44 ] = KEY_KP0, // 10 - [ 0x24 ] = KEY_ENTER, // 11 - [ 0x64 ] = KEY_ESC, // 12 - [ 0x04 ] = KEY_M, // Multi - - [ 0x54 ] = KEY_VIDEO, // VIDEO - [ 0x34 ] = KEY_CHANNELUP, // channel + - [ 0x74 ] = KEY_VOLUMEUP, // volume + - [ 0x14 ] = KEY_MUTE, // Mute - - [ 0x4c ] = KEY_S, // SVIDEO - [ 0x2c ] = KEY_CHANNELDOWN, // channel - - [ 0x6c ] = KEY_VOLUMEDOWN, // volume - - [ 0x0c ] = KEY_ZOOM, // Zoom - - [ 0x5c ] = KEY_PAUSE, // pause - [ 0x3c ] = KEY_C, // || (red) - [ 0x7c ] = KEY_RECORD, // recording - [ 0x1c ] = KEY_STOP, // stop - - [ 0x41 ] = KEY_REWIND, // backward << - [ 0x21 ] = KEY_PLAY, // play - [ 0x61 ] = KEY_FASTFORWARD, // forward >> - [ 0x01 ] = KEY_NEXT, // skip >| + [0x40] = KEY_TV, + [0x20] = KEY_RADIO, /* FM */ + [0x60] = KEY_EPG, + [0x00] = KEY_POWER, + + /* Keys 0 to 9 */ + [0x44] = KEY_KP0, /* 10 */ + [0x50] = KEY_KP1, + [0x30] = KEY_KP2, + [0x70] = KEY_KP3, + [0x48] = KEY_KP4, + [0x28] = KEY_KP5, + [0x68] = KEY_KP6, + [0x58] = KEY_KP7, + [0x38] = KEY_KP8, + [0x78] = KEY_KP9, + + [0x10] = KEY_L, /* Live */ + [0x08] = KEY_T, /* Time Shift */ + + [0x18] = KEY_PLAYPAUSE, /* Play */ + + [0x24] = KEY_ENTER, /* 11 */ + [0x64] = KEY_ESC, /* 12 */ + [0x04] = KEY_M, /* Multi */ + + [0x54] = KEY_VIDEO, + [0x34] = KEY_CHANNELUP, + [0x74] = KEY_VOLUMEUP, + [0x14] = KEY_MUTE, + + [0x4c] = KEY_S, /* SVIDEO */ + [0x2c] = KEY_CHANNELDOWN, + [0x6c] = KEY_VOLUMEDOWN, + [0x0c] = KEY_ZOOM, + + [0x5c] = KEY_PAUSE, + [0x3c] = KEY_C, /* || (red) */ + [0x7c] = KEY_RECORD, /* recording */ + [0x1c] = KEY_STOP, + + [0x41] = KEY_REWIND, /* backward << */ + [0x21] = KEY_PLAY, + [0x61] = KEY_FASTFORWARD, /* forward >> */ + [0x01] = KEY_NEXT, /* skip >| */ }; /* ---------------------------------------------------------------------- */ /* ADS Tech Instant TV DVB-T PCI Remote */ static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = { - [ 0x5b ] = KEY_POWER, - [ 0x5f ] = KEY_MUTE, - [ 0x57 ] = KEY_1, - [ 0x4f ] = KEY_2, - [ 0x53 ] = KEY_3, - [ 0x56 ] = KEY_4, - [ 0x4e ] = KEY_5, - [ 0x5e ] = KEY_6, - [ 0x54 ] = KEY_7, - [ 0x4c ] = KEY_8, - [ 0x5c ] = KEY_9, - [ 0x4d ] = KEY_0, - [ 0x55 ] = KEY_GOTO, - [ 0x5d ] = KEY_SEARCH, - [ 0x17 ] = KEY_EPG, // Guide - [ 0x1f ] = KEY_MENU, - [ 0x0f ] = KEY_UP, - [ 0x46 ] = KEY_DOWN, - [ 0x16 ] = KEY_LEFT, - [ 0x1e ] = KEY_RIGHT, - [ 0x0e ] = KEY_SELECT, // Enter - [ 0x5a ] = KEY_INFO, - [ 0x52 ] = KEY_EXIT, - [ 0x59 ] = KEY_PREVIOUS, - [ 0x51 ] = KEY_NEXT, - [ 0x58 ] = KEY_REWIND, - [ 0x50 ] = KEY_FORWARD, - [ 0x44 ] = KEY_PLAYPAUSE, - [ 0x07 ] = KEY_STOP, - [ 0x1b ] = KEY_RECORD, - [ 0x13 ] = KEY_TUNER, // Live - [ 0x0a ] = KEY_A, - [ 0x12 ] = KEY_B, - [ 0x03 ] = KEY_PROG1, // 1 - [ 0x01 ] = KEY_PROG2, // 2 - [ 0x00 ] = KEY_PROG3, // 3 - [ 0x06 ] = KEY_DVD, - [ 0x48 ] = KEY_AUX, // Photo - [ 0x40 ] = KEY_VIDEO, - [ 0x19 ] = KEY_AUDIO, // Music - [ 0x0b ] = KEY_CHANNELUP, - [ 0x08 ] = KEY_CHANNELDOWN, - [ 0x15 ] = KEY_VOLUMEUP, - [ 0x1c ] = KEY_VOLUMEDOWN, + /* Keys 0 to 9 */ + [0x4d] = KEY_0, + [0x57] = KEY_1, + [0x4f] = KEY_2, + [0x53] = KEY_3, + [0x56] = KEY_4, + [0x4e] = KEY_5, + [0x5e] = KEY_6, + [0x54] = KEY_7, + [0x4c] = KEY_8, + [0x5c] = KEY_9, + + [0x5b] = KEY_POWER, + [0x5f] = KEY_MUTE, + [0x55] = KEY_GOTO, + [0x5d] = KEY_SEARCH, + [0x17] = KEY_EPG, /* Guide */ + [0x1f] = KEY_MENU, + [0x0f] = KEY_UP, + [0x46] = KEY_DOWN, + [0x16] = KEY_LEFT, + [0x1e] = KEY_RIGHT, + [0x0e] = KEY_SELECT, /* Enter */ + [0x5a] = KEY_INFO, + [0x52] = KEY_EXIT, + [0x59] = KEY_PREVIOUS, + [0x51] = KEY_NEXT, + [0x58] = KEY_REWIND, + [0x50] = KEY_FORWARD, + [0x44] = KEY_PLAYPAUSE, + [0x07] = KEY_STOP, + [0x1b] = KEY_RECORD, + [0x13] = KEY_TUNER, /* Live */ + [0x0a] = KEY_A, + [0x12] = KEY_B, + [0x03] = KEY_PROG1, /* 1 */ + [0x01] = KEY_PROG2, /* 2 */ + [0x00] = KEY_PROG3, /* 3 */ + [0x06] = KEY_DVD, + [0x48] = KEY_AUX, /* Photo */ + [0x40] = KEY_VIDEO, + [0x19] = KEY_AUDIO, /* Music */ + [0x0b] = KEY_CHANNELUP, + [0x08] = KEY_CHANNELDOWN, + [0x15] = KEY_VOLUMEUP, + [0x1c] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ /* MSI TV@nywhere remote */ static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_0, /* '0' */ - [ 0x01 ] = KEY_1, /* '1' */ - [ 0x02 ] = KEY_2, /* '2' */ - [ 0x03 ] = KEY_3, /* '3' */ - [ 0x04 ] = KEY_4, /* '4' */ - [ 0x05 ] = KEY_5, /* '5' */ - [ 0x06 ] = KEY_6, /* '6' */ - [ 0x07 ] = KEY_7, /* '7' */ - [ 0x08 ] = KEY_8, /* '8' */ - [ 0x09 ] = KEY_9, /* '9' */ - [ 0x0c ] = KEY_MUTE, /* 'Mute' */ - [ 0x0f ] = KEY_SCREEN, /* 'Full Screen' */ - [ 0x10 ] = KEY_F, /* 'Funtion' */ - [ 0x11 ] = KEY_T, /* 'Time shift' */ - [ 0x12 ] = KEY_POWER, /* 'Power' */ - [ 0x13 ] = KEY_MEDIA, /* 'MTS' */ - [ 0x14 ] = KEY_SLOW, /* 'Slow' */ - [ 0x16 ] = KEY_REWIND, /* 'backward <<' */ - [ 0x17 ] = KEY_ENTER, /* 'Return' */ - [ 0x18 ] = KEY_FASTFORWARD, /* 'forward >>' */ - [ 0x1a ] = KEY_CHANNELUP, /* 'Channel+' */ - [ 0x1b ] = KEY_VOLUMEUP, /* 'Volume+' */ - [ 0x1e ] = KEY_CHANNELDOWN, /* 'Channel-' */ - [ 0x1f ] = KEY_VOLUMEDOWN, /* 'Volume-' */ + /* Keys 0 to 9 */ + [0x00] = KEY_0, + [0x01] = KEY_1, + [0x02] = KEY_2, + [0x03] = KEY_3, + [0x04] = KEY_4, + [0x05] = KEY_5, + [0x06] = KEY_6, + [0x07] = KEY_7, + [0x08] = KEY_8, + [0x09] = KEY_9, + + [0x0c] = KEY_MUTE, + [0x0f] = KEY_SCREEN, /* Full Screen */ + [0x10] = KEY_F, /* Funtion */ + [0x11] = KEY_T, /* Time shift */ + [0x12] = KEY_POWER, + [0x13] = KEY_MEDIA, /* MTS */ + [0x14] = KEY_SLOW, + [0x16] = KEY_REWIND, /* backward << */ + [0x17] = KEY_ENTER, /* Return */ + [0x18] = KEY_FASTFORWARD, /* forward >> */ + [0x1a] = KEY_CHANNELUP, + [0x1b] = KEY_VOLUMEUP, + [0x1e] = KEY_CHANNELDOWN, + [0x1f] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ struct cx88_IR { - struct cx88_core *core; - struct input_dev input; - struct ir_input_state ir; - char name[32]; - char phys[32]; + struct cx88_core *core; + struct input_dev input; + struct ir_input_state ir; + char name[32]; + char phys[32]; /* sample from gpio pin 16 */ - int sampling; - u32 samples[16]; - int scount; - unsigned long release; + int sampling; + u32 samples[16]; + int scount; + unsigned long release; /* poll external decoder */ - int polling; - struct work_struct work; - struct timer_list timer; - u32 gpio_addr; - u32 last_gpio; - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; + int polling; + struct work_struct work; + struct timer_list timer; + u32 gpio_addr; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; }; static int ir_debug = 0; -module_param(ir_debug, int, 0644); /* debug level [IR] */ +module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define ir_dprintk(fmt, arg...) if (ir_debug) \ @@ -254,37 +261,37 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* extract data */ data = ir_extract_bits(gpio, ir->mask_keycode); ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(&ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(&ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(&ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(&ir->input, &ir->ir); } } else { /* can't distinguish keydown/up :-/ */ - ir_input_keydown(&ir->input,&ir->ir,data,data); - ir_input_nokey(&ir->input,&ir->ir); + ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_nokey(&ir->input, &ir->ir); } } static void ir_timer(unsigned long data) { - struct cx88_IR *ir = (struct cx88_IR*)data; + struct cx88_IR *ir = (struct cx88_IR *)data; schedule_work(&ir->work); } @@ -307,62 +314,62 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir),GFP_KERNEL); + ir = kmalloc(sizeof(*ir), GFP_KERNEL); if (NULL == ir) return -ENOMEM; - memset(ir,0,sizeof(*ir)); + memset(ir, 0, sizeof(*ir)); /* detect & configure */ switch (core->board) { case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_KWORLD_DVB_T: - ir_codes = ir_codes_dntv_live_dvb_t; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_dntv_live_dvb_t; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x60; - ir->polling = 50; // ms + ir->mask_keyup = 0x60; + ir->polling = 50; /* ms */ break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - ir_codes = ir_codes_hauppauge_new; - ir_type = IR_TYPE_RC5; - ir->sampling = 1; + ir_codes = ir_codes_hauppauge_new; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; break; case CX88_BOARD_WINFAST2000XP_EXPERT: - ir_codes = ir_codes_winfast; - ir->gpio_addr = MO_GP0_IO; + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; - ir->mask_keyup = 0x100; - ir->polling = 1; // ms + ir->mask_keyup = 0x100; + ir->polling = 1; /* ms */ break; case CX88_BOARD_IODATA_GVBCTV7E: - ir_codes = ir_codes_iodata_bctv7e; - ir->gpio_addr = MO_GP0_IO; + ir_codes = ir_codes_iodata_bctv7e; + ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0xfd; ir->mask_keydown = 0x02; - ir->polling = 5; // ms + ir->polling = 5; /* ms */ break; case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: - ir_codes = ir_codes_pixelview; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_pixelview; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x80; - ir->polling = 1; // ms + ir->mask_keyup = 0x80; + ir->polling = 1; /* ms */ break; case CX88_BOARD_ADSTECH_DVB_T_PCI: - ir_codes = ir_codes_adstech_dvb_t_pci; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_adstech_dvb_t_pci; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0xbf; - ir->mask_keyup = 0x40; - ir->polling = 50; // ms + ir->mask_keyup = 0x40; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + ir_codes = ir_codes_msi_tvanywhere; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x40; + ir->polling = 1; /* ms */ break; - case CX88_BOARD_MSI_TVANYWHERE_MASTER: - ir_codes = ir_codes_msi_tvanywhere; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x40; - ir->polling = 1; - break; } if (NULL == ir_codes) { @@ -373,8 +380,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) /* init input device */ snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", cx88_boards[core->board].name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(pci)); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); ir->input.name = ir->name; @@ -382,10 +388,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input.id.bustype = BUS_PCI; ir->input.id.version = 1; if (pci->subsystem_vendor) { - ir->input.id.vendor = pci->subsystem_vendor; + ir->input.id.vendor = pci->subsystem_vendor; ir->input.id.product = pci->subsystem_device; } else { - ir->input.id.vendor = pci->vendor; + ir->input.id.vendor = pci->vendor; ir->input.id.product = pci->device; } @@ -397,13 +403,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) INIT_WORK(&ir->work, cx88_ir_work, ir); init_timer(&ir->timer); ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; + ir->timer.data = (unsigned long)ir; schedule_work(&ir->work); } if (ir->sampling) { - core->pci_irqmask |= (1<<18); // IR_SMP_INT - cx_write(MO_DDS_IO, 0xa80a80); // 4 kHz sample rate - cx_write(MO_DDSCFG_IO, 0x5); // enable + core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ + cx_write(MO_DDSCFG_IO, 0x5); /* enable */ } /* all done */ @@ -439,7 +445,7 @@ int cx88_ir_fini(struct cx88_core *core) void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; - u32 samples,rc5; + u32 samples, rc5; int i; if (NULL == ir) @@ -448,7 +454,7 @@ void cx88_ir_irq(struct cx88_core *core) return; samples = cx_read(MO_SAMPLE_IO); - if (0 != samples && 0xffffffff != samples) { + if (0 != samples && 0xffffffff != samples) { /* record sample data */ if (ir->scount < ARRAY_SIZE(ir->samples)) ir->samples[ir->scount++] = samples; @@ -456,8 +462,8 @@ void cx88_ir_irq(struct cx88_core *core) } if (!ir->scount) { /* nothing to sample */ - if (ir->ir.keypressed && time_after(jiffies,ir->release)) - ir_input_nokey(&ir->input,&ir->ir); + if (ir->ir.keypressed && time_after(jiffies, ir->release)) + ir_input_nokey(&ir->input, &ir->ir); return; } @@ -467,14 +473,14 @@ void cx88_ir_irq(struct cx88_core *core) for (i = 0; i < ir->scount; i++) ir->samples[i] = ~ir->samples[i]; if (ir_debug) - ir_dump_samples(ir->samples,ir->scount); + ir_dump_samples(ir->samples, ir->scount); /* decode it */ switch (core->board) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7); - ir_dprintk("biphase decoded: %x\n",rc5); + rc5 = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", rc5); if ((rc5 & 0xfffff000) != 0x3000) break; ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 85da6dc8d0e..fe2767c0ff9 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.30 2005/07/05 19:44:40 mkrufky Exp $ + * $Id: cx88-mpeg.c,v 1.31 2005/07/07 14:17:47 mchehab Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -64,7 +64,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* write TS length to chip */ cx_write(MO_TS_LNGTH, buf->vb.width); -#if 1 /* FIXME: this needs a review. * also: move to cx88-blackbird + cx88-dvb source files? */ @@ -76,9 +75,9 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) || (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) { - cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12); + cx_write(TS_SOP_STAT, 1<<13); } else { - cx_write(TS_SOP_STAT,0x00); + cx_write(TS_SOP_STAT, 0x00); } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); @@ -98,7 +97,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ udelay(100); } -#endif /* reset counter */ cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); @@ -270,6 +268,15 @@ static void cx8802_timeout(unsigned long data) do_cancel_buffers(dev,"timeout",1); } +static char *cx88_mpeg_irqs[32] = { + "ts_risci1", NULL, NULL, NULL, + "ts_risci2", NULL, NULL, NULL, + "ts_oflow", NULL, NULL, NULL, + "ts_sync", NULL, NULL, NULL, + "opc_err", "par_err", "rip_err", "pci_abort", + "ts_err?", +}; + static void cx8802_mpeg_irq(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; @@ -282,10 +289,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) return; cx_write(MO_TS_INTSTAT, status); -#if 0 - cx88_print_irqbits(core->name, "irq mpeg ", - cx88_mpeg_irqs, status, mask); -#endif + if (debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq mpeg ", cx88_mpeg_irqs, status, mask); @@ -441,10 +445,8 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); -#if 1 /* FIXME -- shutdown device */ cx88_shutdown(dev->core); -#endif pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -466,10 +468,8 @@ int cx8802_resume_common(struct pci_dev *pci_dev) pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); -#if 1 /* FIXME: re-initialize hardware */ cx88_reset(dev->core); -#endif /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 63ad33f5818..37f82662d26 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -1,5 +1,5 @@ /* - $Id: cx88-reg.h,v 1.7 2005/06/03 13:31:51 mchehab Exp $ + $Id: cx88-reg.h,v 1.8 2005/07/07 13:58:38 mchehab Exp $ cx88x-hw.h - CX2388x register offsets @@ -604,20 +604,11 @@ #define EN_I2SIN_STR2DAC 0x00004000 #define EN_I2SIN_ENABLE 0x00008000 -#if 0 -/* old */ -#define EN_DMTRX_SUMDIFF 0x00000800 -#define EN_DMTRX_SUMR 0x00000880 -#define EN_DMTRX_LR 0x00000900 -#define EN_DMTRX_MONO 0x00000980 -#else -/* dscaler cvs */ #define EN_DMTRX_SUMDIFF (0 << 7) #define EN_DMTRX_SUMR (1 << 7) #define EN_DMTRX_LR (2 << 7) #define EN_DMTRX_MONO (3 << 7) #define EN_DMTRX_BYPASS (1 << 11) -#endif // Video #define VID_CAPTURE_CONTROL 0x310180 diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 46d78b1dc9b..91207f10bae 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -1,5 +1,5 @@ /* - $Id: cx88-tvaudio.c,v 1.36 2005/06/05 05:53:45 mchehab Exp $ + $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -278,80 +278,6 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) set_audio_finish(core); } -#if 0 -static void set_audio_standard_NICAM(struct cx88_core *core) -{ - static const struct rlist nicam_common[] = { - /* from dscaler */ - { AUD_RATE_ADJ1, 0x00000010 }, - { AUD_RATE_ADJ2, 0x00000040 }, - { AUD_RATE_ADJ3, 0x00000100 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00001000 }, - // { AUD_DMD_RA_DDS, 0x00c0d5ce }, - - // Deemphasis 1: - { AUD_DEEMPHGAIN_R, 0x000023c2 }, - { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, - { AUD_DEEMPHNUMER2_R, 0x0003023e }, - { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - -#if 0 - // Deemphasis 2: (other tv norm?) - { AUD_DEEMPHGAIN_R, 0x0000c600 }, - { AUD_DEEMPHNUMER1_R, 0x00066738 }, - { AUD_DEEMPHNUMER2_R, 0x00066739 }, - { AUD_DEEMPHDENOM1_R, 0x0001e88c }, - { AUD_DEEMPHDENOM2_R, 0x0001e88c }, -#endif - - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000fff }, - { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, - { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - - // setup QAM registers - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_QAM_MODE, 0x05 }, - - { /* end of list */ }, - }; - static const struct rlist nicam_pal_i[] = { - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x93 }, - - { /* end of list */ }, - }; - static const struct rlist nicam_default[] = { - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4c }, - - { /* end of list */ }, - }; - - set_audio_start(core, 0x0010, - EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); - set_audio_registers(core, nicam_common); - switch (core->tvaudio) { - case WW_NICAM_I: - dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, nicam_pal_i); - break; - case WW_NICAM_BGDKL: - dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, nicam_default); - break; - }; - set_audio_finish(core); -} -#endif static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index dc997549b63..c44a079d08c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $ + * $Id: cx88-video.c,v 1.79 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -86,13 +86,6 @@ static struct cx88_tvnorm tvnorms[] = { .id = V4L2_STD_NTSC_M_JP, .cxiformat = VideoFormatNTSCJapan, .cxoformat = 0x181f0008, -#if 0 - },{ - .name = "NTSC-4.43", - .id = FIXME, - .cxiformat = VideoFormatNTSC443, - .cxoformat = 0x181f0008, -#endif },{ .name = "PAL-BG", .id = V4L2_STD_PAL_BG, @@ -248,6 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, }, + .off = 0, .reg = MO_CONTR_BRIGHT, .mask = 0xff00, .shift = 8, @@ -674,231 +668,6 @@ static struct videobuf_queue_ops cx8800_video_qops = { /* ------------------------------------------------------------------ */ -#if 0 /* overlay support not finished yet */ -static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh, - u32 *rp, struct btcx_skiplist *skips, - u32 sync_line, int skip_even, int skip_odd) -{ - int line,maxy,start,end,skip,nskips; - u32 ri,ra; - u32 addr; - - /* sync instruction */ - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - addr = (unsigned long)dev->fbuf.base; - addr += dev->fbuf.fmt.bytesperline * fh->win.w.top; - addr += (fh->fmt->depth >> 3) * fh->win.w.left; - - /* scan lines */ - for (maxy = -1, line = 0; line < fh->win.w.height; - line++, addr += dev->fbuf.fmt.bytesperline) { - if ((line%2) == 0 && skip_even) - continue; - if ((line%2) == 1 && skip_odd) - continue; - - /* calculate clipping */ - if (line > maxy) - btcx_calc_skips(line, fh->win.w.width, &maxy, - skips, &nskips, fh->clips, fh->nclips); - - /* write out risc code */ - for (start = 0, skip = 0; start < fh->win.w.width; start = end) { - if (skip >= nskips) { - ri = RISC_WRITE; - end = fh->win.w.width; - } else if (start < skips[skip].start) { - ri = RISC_WRITE; - end = skips[skip].start; - } else { - ri = RISC_SKIP; - end = skips[skip].end; - skip++; - } - if (RISC_WRITE == ri) - ra = addr + (fh->fmt->depth>>3)*start; - else - ra = 0; - - if (0 == start) - ri |= RISC_SOL; - if (fh->win.w.width == end) - ri |= RISC_EOL; - ri |= (fh->fmt->depth>>3) * (end-start); - - *(rp++)=cpu_to_le32(ri); - if (0 != ra) - *(rp++)=cpu_to_le32(ra); - } - } - kfree(skips); - return rp; -} - -static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct cx88_buffer *buf) -{ - struct btcx_skiplist *skips; - u32 instructions,fields; - u32 *rp; - int rc; - - /* skip list for window clipping */ - if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL))) - return -ENOMEM; - - fields = 0; - if (V4L2_FIELD_HAS_TOP(fh->win.field)) - fields++; - if (V4L2_FIELD_HAS_BOTTOM(fh->win.field)) - fields++; - - /* estimate risc mem: worst case is (clip+1) * lines instructions - + syncs + jump (all 2 dwords) */ - instructions = (fh->nclips+1) * fh->win.w.height; - instructions += 3 + 4; - if ((rc = btcx_riscmem_alloc(dev->pci,&buf->risc,instructions*8)) < 0) { - kfree(skips); - return rc; - } - - /* write risc instructions */ - rp = buf->risc.cpu; - switch (fh->win.field) { - case V4L2_FIELD_TOP: - rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 0); - break; - case V4L2_FIELD_BOTTOM: - rp = ov_risc_field(dev, fh, rp, skips, 0x200, 0, 0); - break; - case V4L2_FIELD_INTERLACED: - rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 1); - rp = ov_risc_field(dev, fh, rp, skips, 0x200, 1, 0); - break; - default: - BUG(); - } - - /* save pointer to jmp instruction address */ - buf->risc.jmp = rp; - kfree(skips); - return 0; -} - -static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win) -{ - enum v4l2_field field; - int maxw, maxh; - - if (NULL == dev->fbuf.base) - return -EINVAL; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - if (win->clipcount > 2048) - return -EINVAL; - - field = win->field; - maxw = norm_maxw(core->tvnorm); - maxh = norm_maxh(core->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - return 0; -} - -static int setup_window(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct v4l2_window *win) -{ - struct v4l2_clip *clips = NULL; - int n,size,retval = 0; - - if (NULL == fh->fmt) - return -EINVAL; - retval = verify_window(dev,win); - if (0 != retval) - return retval; - - /* copy clips -- luckily v4l1 + v4l2 are binary - compatible here ...*/ - n = win->clipcount; - size = sizeof(*clips)*(n+4); - clips = kmalloc(size,GFP_KERNEL); - if (NULL == clips) - return -ENOMEM; - if (n > 0) { - if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { - kfree(clips); - return -EFAULT; - } - } - - /* clip against screen */ - if (NULL != dev->fbuf.base) - n = btcx_screen_clips(dev->fbuf.fmt.width, dev->fbuf.fmt.height, - &win->w, clips, n); - btcx_sort_clips(clips,n); - - /* 4-byte alignments */ - switch (fh->fmt->depth) { - case 8: - case 24: - btcx_align(&win->w, clips, n, 3); - break; - case 16: - btcx_align(&win->w, clips, n, 1); - break; - case 32: - /* no alignment fixups needed */ - break; - default: - BUG(); - } - - down(&fh->vidq.lock); - if (fh->clips) - kfree(fh->clips); - fh->clips = clips; - fh->nclips = n; - fh->win = *win; -#if 0 - fh->ov.setup_ok = 1; -#endif - - /* update overlay if needed */ - retval = 0; -#if 0 - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_alloc(sizeof(*new)); - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv,fh,new); - } -#endif - up(&fh->vidq.lock); - return retval; -} -#endif /* ------------------------------------------------------------------ */ @@ -1327,9 +1096,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; -#if 0 - unsigned long flags; -#endif int err; if (video_debug > 1) @@ -1350,9 +1116,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | -#if 0 - V4L2_CAP_VIDEO_OVERLAY | -#endif 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; @@ -1453,36 +1216,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } -#if 0 - /* needs review */ - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int n = a->index; - - memset(a,0,sizeof(*a)); - a->index = n; - switch (n) { - case 0: - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) - || (CX88_VMUX_CABLE == INPUT(n)->type)) { - strcpy(a->name,"Television"); - // FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. - return 0; - } - break; - case 1: - if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { - strcpy(a->name,"Line In"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; - } - break; - } - // Audio input not available. - return -EINVAL; - } -#endif /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: @@ -1592,6 +1325,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; + + cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f); + return 0; } case VIDIOC_S_FREQUENCY: @@ -1846,6 +1582,14 @@ static void cx8800_vid_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } +static char *cx88_vid_irqs[32] = { + "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", + "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", + "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", + "y_sync", "u_sync", "v_sync", "vbi_sync", + "opc_err", "par_err", "rip_err", "pci_abort", +}; + static void cx8800_vid_irq(struct cx8800_dev *dev) { struct cx88_core *core = dev->core; @@ -2013,7 +1757,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, { struct cx8800_dev *dev; struct cx88_core *core; - struct tuner_addr tun_addr; int err; dev = kmalloc(sizeof(*dev),GFP_KERNEL); @@ -2087,22 +1830,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (core->tda9887_conf) request_module("tda9887"); - if (core->radio_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_RADIO; - tun_addr.type = core->radio_type; - tun_addr.addr = core->radio_addr; - cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); - } - if (core->tuner_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV; - tun_addr.type = core->tuner_type; - tun_addr.addr = core->tuner_addr; - cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); - } - - if (core->tda9887_conf) - cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf); - /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); @@ -2212,10 +1939,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); -#if 1 /* FIXME -- shutdown device */ cx88_shutdown(dev->core); -#endif pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -2237,10 +1962,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); -#if 1 /* FIXME: re-initialize hardware */ cx88_reset(dev->core); -#endif /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index bc5e038bc0f..307beae04f2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.67 2005/07/01 12:10:07 mkrufky Exp $ + * $Id: cx88.h,v 1.68 2005/07/07 14:17:47 mchehab Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -82,9 +82,9 @@ struct cx88_tvnorm { static unsigned int inline norm_maxw(struct cx88_tvnorm *norm) { return (norm->id & V4L2_STD_625_50) ? 768 : 640; -// return (norm->id & V4L2_STD_625_50) ? 720 : 640; } + static unsigned int inline norm_maxh(struct cx88_tvnorm *norm) { return (norm->id & V4L2_STD_625_50) ? 576 : 480; @@ -220,7 +220,6 @@ struct cx88_subid { #define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ -//#define BUFFER_TIMEOUT (HZ*2) /* buffer for one video frame */ struct cx88_buffer { @@ -336,11 +335,6 @@ struct cx8800_dev { struct pci_dev *pci; unsigned char pci_rev,pci_lat; -#if 0 - /* video overlay */ - struct v4l2_framebuffer fbuf; - struct cx88_buffer *screen; -#endif /* capture queues */ struct cx88_dmaqueue vidq; @@ -435,8 +429,6 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ /* cx88-core.c */ -extern char *cx88_vid_irqs[32]; -extern char *cx88_mpeg_irqs[32]; extern void cx88_print_irqbits(char *name, char *tag, char **strings, u32 bits, u32 mask); extern void cx88_print_ioctl(char *name, unsigned int cmd); -- cgit v1.2.3 From 86ddd96fcd479ec4b718abaa661e5884f9dc9a33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:47 -0700 Subject: [PATCH] v4l: SAA7134 hybrid DVB - Add new Typhoon DVB-T Cardbus. - DVB-T support for MD7134 cardbus and the PCI variants - initial DVB-T support for Lifeview Flydvb-t duo - DVB-T support for Philips TOUGH reference design - Don't turn off the xtal output of tda8274/75 in sleep mode - Let Kconfig decide whether to include frontend-specific code in saa7134-dvb. - Removed unused structures. Signed-off-by: Juergen Orschiedt Signed-off-by: Michael Krufky Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa6752hs.c | 4 - drivers/media/video/saa7134/saa7134-dvb.c | 420 +++++++++++++++++++++++++++--- 2 files changed, 389 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index e6d0a18833d..79d05ea1b69 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -155,10 +155,6 @@ static struct v4l2_mpeg_compression param_defaults = .target = 256, }, -#if 0 - /* FIXME: size? via S_FMT? */ - .video_format = MPEG_VIDEO_FORMAT_D1, -#endif }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index aa8e2cf62d5..3959a571486 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1,8 +1,11 @@ /* - * $Id: saa7134-dvb.c,v 1.13 2005/06/12 04:19:19 mchehab Exp $ + * $Id: saa7134-dvb.c,v 1.18 2005/07/04 16:05:50 mkrufky Exp $ * * (c) 2004 Gerd Knorr [SuSE Labs] * + * Extended 3 / 2005 by Hartmut Hackmann to support various + * cards with the tda10046 DVB-T channel decoder + * * 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 @@ -30,20 +33,25 @@ #include "saa7134-reg.h" #include "saa7134.h" -#include "dvb-pll.h" -#include "mt352.h" -#include "mt352_priv.h" /* FIXME */ -#include "tda1004x.h" +#if CONFIG_DVB_MT352 +# include "mt352.h" +# include "mt352_priv.h" /* FIXME */ +#endif +#if CONFIG_DVB_TDA1004X +# include "tda1004x.h" +#endif MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); static unsigned int antenna_pwr = 0; + module_param(antenna_pwr, int, 0444); MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); /* ------------------------------------------------------------------ */ +#if CONFIG_DVB_MT352 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) { u32 ok; @@ -138,48 +146,387 @@ static struct mt352_config pinnacle_300i = { .demod_init = mt352_pinnacle_init, .pll_set = mt352_pinnacle_pll_set, }; +#endif /* ------------------------------------------------------------------ */ -static int medion_cardbus_init(struct dvb_frontend* fe) +#if CONFIG_DVB_TDA1004X +static int philips_tu1216_pll_init(struct dvb_frontend *fe) { - /* anything to do here ??? */ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; + + /* setup PLL configuration */ + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + return 0; } -static int medion_cardbus_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; - struct v4l2_frequency f; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + /* determine charge pump */ + tuner_frequency = params->frequency + 36166000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + /* determine band */ + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 161000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + /* setup PLL filter */ + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + filter = 1; + break; - /* - * this instructs tuner.o to set the frequency, the call will - * end up in tuner_command(), VIDIOC_S_FREQUENCY switch. - * tda9887.o will see that as well. + default: + return -EINVAL; + } + + /* calculate divisor + * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) */ - f.tuner = 0; - f.type = V4L2_TUNER_DIGITAL_TV; - f.frequency = params->frequency / 1000 * 16 / 1000; - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + + /* setup tuner buffer */ + tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); return 0; } -static int fe_request_firmware(struct dvb_frontend* fe, - const struct firmware **fw, char* name) +static int philips_tu1216_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) { struct saa7134_dev *dev = fe->dvb->priv; return request_firmware(fw, name, &dev->pci->dev); } +static struct tda1004x_config philips_tu1216_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .pll_init = philips_tu1216_pll_init, + .pll_set = philips_tu1216_pll_set, + .pll_sleep = NULL, + .request_firmware = philips_tu1216_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + + +static int philips_fmd1216_pll_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* this message is to set up ATC and ALC */ + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + return 0; +} + +static void philips_fmd1216_analog(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* this message actually turns the tuner back to analog mode */ + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + msleep(1); + fmd1216_init[2] = 0x86; + fmd1216_init[3] = 0x54; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + msleep(1); +} + +static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + int divider = 0; + u8 band, mode, cp; + + /* determine charge pump */ + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + /* low band */ + else if (tuner_frequency < 180000000) { + band = 1; + mode = 7; + cp = 0; + } else if (tuner_frequency < 195000000) { + band = 1; + mode = 6; + cp = 1; + /* mid band */ + } else if (tuner_frequency < 366000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 10; + } else { + band = 2; + } + mode = 7; + cp = 0; + } else if (tuner_frequency < 478000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 10; + } else { + band = 2; + } + mode = 6; + cp = 1; + /* high band */ + } else if (tuner_frequency < 662000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 7; + cp = 0; + } else if (tuner_frequency < 840000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 6; + cp = 1; + } else { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 7; + cp = 1; + + } + /* calculate divisor */ + /* ((36166000 + Finput) / 166666) rounded! */ + divider = (tuner_frequency + 83333) / 166667; + + /* setup tuner buffer */ + tuner_buf[0] = (divider >> 8) & 0x7f; + tuner_buf[1] = divider & 0xff; + tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4; + tuner_buf[3] = 0x40 | band; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + return 0; +} + + static struct tda1004x_config medion_cardbus = { - .demod_address = 0x08, /* not sure this is correct */ - .invert = 0, - .invert_oclk = 0, - .pll_init = medion_cardbus_init, - .pll_set = medion_cardbus_pll_set, - .request_firmware = fe_request_firmware, + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_IFO_AUTO_NEG, + .if_freq = TDA10046_FREQ_3613, + .pll_init = philips_fmd1216_pll_init, + .pll_set = philips_fmd1216_pll_set, + .pll_sleep = philips_fmd1216_analog, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + +static struct tda827x_data tda827x_dvbt[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int philips_tda827x_pll_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[14]; + + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int i, tuner_freq, if_freq; + u32 N; + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827x_dvbt[i].lomax < tuner_freq) { + if(tda827x_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + tuner_buf[0] = 0; + tuner_buf[1] = (N>>8) | 0x40; + tuner_buf[2] = N & 0xff; + tuner_buf[3] = 0; + tuner_buf[4] = 0x52; + tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + + (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; + tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + tuner_buf[7] = 0xbf; + tuner_buf[8] = 0x2a; + tuner_buf[9] = 0x05; + tuner_buf[10] = 0xff; + tuner_buf[11] = 0x00; + tuner_buf[12] = 0x00; + tuner_buf[13] = 0x40; + + tuner_msg.len = 14; + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(500); + /* correct CP value */ + tuner_buf[0] = 0x30; + tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp; + tuner_msg.len = 2; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + + return 0; +} + +static void philips_tda827x_pll_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda827x_sleep[] = { 0x30, 0xd0}; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, + .len = sizeof(tda827x_sleep) }; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); +} + +static struct tda1004x_config tda827x_lifeview_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .pll_init = philips_tda827x_pll_init, + .pll_set = philips_tda827x_pll_set, + .pll_sleep = philips_tda827x_pll_sleep, + .request_firmware = NULL, }; +#endif /* ------------------------------------------------------------------ */ @@ -197,18 +544,31 @@ static int dvb_init(struct saa7134_dev *dev) dev); switch (dev->board) { +#if CONFIG_DVB_MT352 case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: printk("%s: pinnacle 300i dvb setup\n",dev->name); dev->dvb.frontend = mt352_attach(&pinnacle_300i, &dev->i2c_adap); break; +#endif +#if CONFIG_DVB_TDA1004X case SAA7134_BOARD_MD7134: dev->dvb.frontend = tda10046_attach(&medion_cardbus, &dev->i2c_adap); - if (NULL == dev->dvb.frontend) - printk("%s: Hmm, looks like this is the old MD7134 " - "version without DVB-T support\n",dev->name); break; + case SAA7134_BOARD_PHILIPS_TOUGH: + dev->dvb.frontend = tda10046_attach(&philips_tu1216_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_FLYDVBTDUO: + dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS: + dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, + &dev->i2c_adap); + break; +#endif default: printk("%s: Huh? unknown DVB card?\n",dev->name); break; @@ -227,8 +587,6 @@ static int dvb_fini(struct saa7134_dev *dev) { static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; - printk("%s: %s\n",dev->name,__FUNCTION__); - switch (dev->board) { case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ -- cgit v1.2.3 From 5f8434a620383eec1115e73fdb18c53e049b26b9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:51 -0700 Subject: [PATCH] v4l: I2C BT832 - Removed unused structures. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bt832.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index 9a642c7de54..a070417e65e 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -138,25 +138,13 @@ int bt832_init(struct i2c_client *i2c_client_s) bt832_hexdump(i2c_client_s,buf); -#if 0 - // Full 30/25 Frame rate - printk("Full 30/25 Frame rate\n"); - buf[0]=BT832_VP_CONTROL0; // Reg.39 - buf[1]= 0x00; - if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error FFR: rc == %d (should be 2)\n",rc); - - bt832_hexdump(i2c_client_s,buf); -#endif -#if 1 // for testing (even works when no camera attached) printk("bt832: *** Generate NTSC M Bars *****\n"); buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42 buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc); -#endif printk("Bt832: Camera Present: %s\n", (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no"); -- cgit v1.2.3 From 60acbc99e82753b0baa64834435caf81eabc2501 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:52 -0700 Subject: [PATCH] v4l: I2C Infrared Remote Control - Removed unused structures. - CodingStyle rules applied to comments. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/common/ir-common.c | 255 +++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index 4adb2843f8b..ab7a1fba442 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -1,5 +1,5 @@ /* - * $Id: ir-common.c,v 1.10 2005/05/22 19:23:39 nsh Exp $ + * $Id: ir-common.c,v 1.11 2005/07/07 14:44:43 mchehab Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -46,79 +46,49 @@ module_param(debug, int, 0644); /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ /* used by old (black) Hauppauge remotes */ IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_KP0, // 0 - [ 0x01 ] = KEY_KP1, // 1 - [ 0x02 ] = KEY_KP2, // 2 - [ 0x03 ] = KEY_KP3, // 3 - [ 0x04 ] = KEY_KP4, // 4 - [ 0x05 ] = KEY_KP5, // 5 - [ 0x06 ] = KEY_KP6, // 6 - [ 0x07 ] = KEY_KP7, // 7 - [ 0x08 ] = KEY_KP8, // 8 - [ 0x09 ] = KEY_KP9, // 9 - - [ 0x0b ] = KEY_CHANNEL, // channel / program (japan: 11) - [ 0x0c ] = KEY_POWER, // standby - [ 0x0d ] = KEY_MUTE, // mute / demute - [ 0x0f ] = KEY_TV, // display - [ 0x10 ] = KEY_VOLUMEUP, // volume + - [ 0x11 ] = KEY_VOLUMEDOWN, // volume - - [ 0x12 ] = KEY_BRIGHTNESSUP, // brightness + - [ 0x13 ] = KEY_BRIGHTNESSDOWN, // brightness - - [ 0x1e ] = KEY_SEARCH, // search + - [ 0x20 ] = KEY_CHANNELUP, // channel / program + - [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - - [ 0x22 ] = KEY_CHANNEL, // alt / channel - [ 0x23 ] = KEY_LANGUAGE, // 1st / 2nd language - [ 0x26 ] = KEY_SLEEP, // sleeptimer - [ 0x2e ] = KEY_MENU, // 2nd controls (USA: menu) - [ 0x30 ] = KEY_PAUSE, // pause - [ 0x32 ] = KEY_REWIND, // rewind - [ 0x33 ] = KEY_GOTO, // go to - [ 0x35 ] = KEY_PLAY, // play - [ 0x36 ] = KEY_STOP, // stop - [ 0x37 ] = KEY_RECORD, // recording - [ 0x3c ] = KEY_TEXT, // teletext submode (Japan: 12) - [ 0x3d ] = KEY_SUSPEND, // system standby - -#if 0 /* FIXME */ - [ 0x0a ] = KEY_RESERVED, // 1/2/3 digits (japan: 10) - [ 0x0e ] = KEY_RESERVED, // P.P. (personal preference) - [ 0x14 ] = KEY_RESERVED, // colour saturation + - [ 0x15 ] = KEY_RESERVED, // colour saturation - - [ 0x16 ] = KEY_RESERVED, // bass + - [ 0x17 ] = KEY_RESERVED, // bass - - [ 0x18 ] = KEY_RESERVED, // treble + - [ 0x19 ] = KEY_RESERVED, // treble - - [ 0x1a ] = KEY_RESERVED, // balance right - [ 0x1b ] = KEY_RESERVED, // balance left - [ 0x1c ] = KEY_RESERVED, // contrast + - [ 0x1d ] = KEY_RESERVED, // contrast - - [ 0x1f ] = KEY_RESERVED, // tint/hue + - [ 0x24 ] = KEY_RESERVED, // spacial stereo on/off - [ 0x25 ] = KEY_RESERVED, // mono / stereo (USA) - [ 0x27 ] = KEY_RESERVED, // tint / hue - - [ 0x28 ] = KEY_RESERVED, // RF switch/PIP select - [ 0x29 ] = KEY_RESERVED, // vote - [ 0x2a ] = KEY_RESERVED, // timed page/channel clck - [ 0x2b ] = KEY_RESERVED, // increment (USA) - [ 0x2c ] = KEY_RESERVED, // decrement (USA) - [ 0x2d ] = KEY_RESERVED, // - [ 0x2f ] = KEY_RESERVED, // PIP shift - [ 0x31 ] = KEY_RESERVED, // erase - [ 0x34 ] = KEY_RESERVED, // wind - [ 0x38 ] = KEY_RESERVED, // external 1 - [ 0x39 ] = KEY_RESERVED, // external 2 - [ 0x3a ] = KEY_RESERVED, // PIP display mode - [ 0x3b ] = KEY_RESERVED, // view data mode / advance - [ 0x3e ] = KEY_RESERVED, // crispener on/off - [ 0x3f ] = KEY_RESERVED, // system select -#endif + /* Keys 0 to 9 */ + [ 0x00 ] = KEY_KP0, + [ 0x01 ] = KEY_KP1, + [ 0x02 ] = KEY_KP2, + [ 0x03 ] = KEY_KP3, + [ 0x04 ] = KEY_KP4, + [ 0x05 ] = KEY_KP5, + [ 0x06 ] = KEY_KP6, + [ 0x07 ] = KEY_KP7, + [ 0x08 ] = KEY_KP8, + [ 0x09 ] = KEY_KP9, + + [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */ + [ 0x0c ] = KEY_POWER, /* standby */ + [ 0x0d ] = KEY_MUTE, /* mute / demute */ + [ 0x0f ] = KEY_TV, /* display */ + [ 0x10 ] = KEY_VOLUMEUP, + [ 0x11 ] = KEY_VOLUMEDOWN, + [ 0x12 ] = KEY_BRIGHTNESSUP, + [ 0x13 ] = KEY_BRIGHTNESSDOWN, + [ 0x1e ] = KEY_SEARCH, /* search + */ + [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ + [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ + [ 0x22 ] = KEY_CHANNEL, /* alt / channel */ + [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */ + [ 0x26 ] = KEY_SLEEP, /* sleeptimer */ + [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */ + [ 0x30 ] = KEY_PAUSE, + [ 0x32 ] = KEY_REWIND, + [ 0x33 ] = KEY_GOTO, + [ 0x35 ] = KEY_PLAY, + [ 0x36 ] = KEY_STOP, + [ 0x37 ] = KEY_RECORD, /* recording */ + [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */ + [ 0x3d ] = KEY_SUSPEND, /* system standby */ + }; EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { + /* Keys 0 to 9 */ + [ 18 ] = KEY_KP0, [ 5 ] = KEY_KP1, [ 6 ] = KEY_KP2, [ 7 ] = KEY_KP3, @@ -128,39 +98,31 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 13 ] = KEY_KP7, [ 14 ] = KEY_KP8, [ 15 ] = KEY_KP9, - [ 18 ] = KEY_KP0, [ 0 ] = KEY_POWER, -// [ 27 ] = MTS button - [ 2 ] = KEY_TUNER, // TV/FM + [ 2 ] = KEY_TUNER, /* TV/FM */ [ 30 ] = KEY_VIDEO, -// [ 22 ] = display button [ 4 ] = KEY_VOLUMEUP, [ 8 ] = KEY_VOLUMEDOWN, [ 12 ] = KEY_CHANNELUP, [ 16 ] = KEY_CHANNELDOWN, - [ 3 ] = KEY_ZOOM, // fullscreen - [ 31 ] = KEY_SUBTITLE, // closed caption/teletext + [ 3 ] = KEY_ZOOM, /* fullscreen */ + [ 31 ] = KEY_SUBTITLE, /* closed caption/teletext */ [ 32 ] = KEY_SLEEP, -// [ 41 ] = boss key [ 20 ] = KEY_MUTE, [ 43 ] = KEY_RED, [ 44 ] = KEY_GREEN, [ 45 ] = KEY_YELLOW, [ 46 ] = KEY_BLUE, - [ 24 ] = KEY_KPPLUS, //fine tune + - [ 25 ] = KEY_KPMINUS, //fine tune - -// [ 42 ] = picture in picture + [ 24 ] = KEY_KPPLUS, /* fine tune + */ + [ 25 ] = KEY_KPMINUS, /* fine tune - */ [ 33 ] = KEY_KPDOT, [ 19 ] = KEY_KPENTER, -// [ 17 ] = recall [ 34 ] = KEY_BACK, [ 35 ] = KEY_PLAYPAUSE, [ 36 ] = KEY_NEXT, -// [ 37 ] = time shifting [ 38 ] = KEY_STOP, [ 39 ] = KEY_RECORD -// [ 40 ] = snapshot }; EXPORT_SYMBOL_GPL(ir_codes_winfast); @@ -174,54 +136,61 @@ EXPORT_SYMBOL_GPL(ir_codes_empty); * slightly different versions), shipped with cx88+ivtv cards. * almost rc5 coding, but some non-standard keys */ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_KP0, // 0 - [ 0x01 ] = KEY_KP1, // 1 - [ 0x02 ] = KEY_KP2, // 2 - [ 0x03 ] = KEY_KP3, // 3 - [ 0x04 ] = KEY_KP4, // 4 - [ 0x05 ] = KEY_KP5, // 5 - [ 0x06 ] = KEY_KP6, // 6 - [ 0x07 ] = KEY_KP7, // 7 - [ 0x08 ] = KEY_KP8, // 8 - [ 0x09 ] = KEY_KP9, // 9 - [ 0x0a ] = KEY_TEXT, // keypad asterisk as well - [ 0x0b ] = KEY_RED, // red button - [ 0x0c ] = KEY_RADIO, // radio - [ 0x0d ] = KEY_MENU, // menu - [ 0x0e ] = KEY_SUBTITLE, // also the # key - [ 0x0f ] = KEY_MUTE, // mute - [ 0x10 ] = KEY_VOLUMEUP, // volume + - [ 0x11 ] = KEY_VOLUMEDOWN, // volume - - [ 0x12 ] = KEY_PREVIOUS, // previous channel - [ 0x14 ] = KEY_UP, // up - [ 0x15 ] = KEY_DOWN, // down - [ 0x16 ] = KEY_LEFT, // left - [ 0x17 ] = KEY_RIGHT, // right - [ 0x18 ] = KEY_VIDEO, // Videos - [ 0x19 ] = KEY_AUDIO, // Music - [ 0x1a ] = KEY_MHP, // Pictures - presume this means "Multimedia Home Platform"- no "PICTURES" key in input.h - [ 0x1b ] = KEY_EPG, // Guide - [ 0x1c ] = KEY_TV, // TV - [ 0x1e ] = KEY_NEXTSONG, // skip >| - [ 0x1f ] = KEY_EXIT, // back/exit - [ 0x20 ] = KEY_CHANNELUP, // channel / program + - [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - - [ 0x22 ] = KEY_CHANNEL, // source (old black remote) - [ 0x24 ] = KEY_PREVIOUSSONG, // replay |< - [ 0x25 ] = KEY_ENTER, // OK - [ 0x26 ] = KEY_SLEEP, // minimize (old black remote) - [ 0x29 ] = KEY_BLUE, // blue key - [ 0x2e ] = KEY_GREEN, // green button - [ 0x30 ] = KEY_PAUSE, // pause - [ 0x32 ] = KEY_REWIND, // backward << - [ 0x34 ] = KEY_FASTFORWARD, // forward >> - [ 0x35 ] = KEY_PLAY, // play - [ 0x36 ] = KEY_STOP, // stop - [ 0x37 ] = KEY_RECORD, // recording - [ 0x38 ] = KEY_YELLOW, // yellow key - [ 0x3b ] = KEY_SELECT, // top right button - [ 0x3c ] = KEY_ZOOM, // full - [ 0x3d ] = KEY_POWER, // system power (green button) + /* Keys 0 to 9 */ + [ 0x00 ] = KEY_KP0, + [ 0x01 ] = KEY_KP1, + [ 0x02 ] = KEY_KP2, + [ 0x03 ] = KEY_KP3, + [ 0x04 ] = KEY_KP4, + [ 0x05 ] = KEY_KP5, + [ 0x06 ] = KEY_KP6, + [ 0x07 ] = KEY_KP7, + [ 0x08 ] = KEY_KP8, + [ 0x09 ] = KEY_KP9, + + [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */ + [ 0x0b ] = KEY_RED, /* red button */ + [ 0x0c ] = KEY_RADIO, + [ 0x0d ] = KEY_MENU, + [ 0x0e ] = KEY_SUBTITLE, /* also the # key */ + [ 0x0f ] = KEY_MUTE, + [ 0x10 ] = KEY_VOLUMEUP, + [ 0x11 ] = KEY_VOLUMEDOWN, + [ 0x12 ] = KEY_PREVIOUS, /* previous channel */ + [ 0x14 ] = KEY_UP, + [ 0x15 ] = KEY_DOWN, + [ 0x16 ] = KEY_LEFT, + [ 0x17 ] = KEY_RIGHT, + [ 0x18 ] = KEY_VIDEO, /* Videos */ + [ 0x19 ] = KEY_AUDIO, /* Music */ + /* 0x1a: Pictures - presume this means + "Multimedia Home Platform" - + no "PICTURES" key in input.h + */ + [ 0x1a ] = KEY_MHP, + + [ 0x1b ] = KEY_EPG, /* Guide */ + [ 0x1c ] = KEY_TV, + [ 0x1e ] = KEY_NEXTSONG, /* skip >| */ + [ 0x1f ] = KEY_EXIT, /* back/exit */ + [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ + [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ + [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */ + [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */ + [ 0x25 ] = KEY_ENTER, /* OK */ + [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */ + [ 0x29 ] = KEY_BLUE, /* blue key */ + [ 0x2e ] = KEY_GREEN, /* green button */ + [ 0x30 ] = KEY_PAUSE, /* pause */ + [ 0x32 ] = KEY_REWIND, /* backward << */ + [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */ + [ 0x35 ] = KEY_PLAY, + [ 0x36 ] = KEY_STOP, + [ 0x37 ] = KEY_RECORD, /* recording */ + [ 0x38 ] = KEY_YELLOW, /* yellow key */ + [ 0x3b ] = KEY_SELECT, /* top right button */ + [ 0x3c ] = KEY_ZOOM, /* full */ + [ 0x3d ] = KEY_POWER, /* system power (green button) */ }; EXPORT_SYMBOL(ir_codes_hauppauge_new); @@ -237,9 +206,9 @@ IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { [ 10 ] = KEY_KP8, [ 18 ] = KEY_KP9, - [ 3 ] = KEY_TUNER, // TV/FM - [ 7 ] = KEY_SEARCH, // scan - [ 28 ] = KEY_ZOOM, // full screen + [ 3 ] = KEY_TUNER, /* TV/FM */ + [ 7 ] = KEY_SEARCH, /* scan */ + [ 28 ] = KEY_ZOOM, /* full screen */ [ 30 ] = KEY_POWER, [ 23 ] = KEY_VOLUMEDOWN, [ 31 ] = KEY_VOLUMEUP, @@ -247,14 +216,14 @@ IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { [ 22 ] = KEY_CHANNELUP, [ 24 ] = KEY_MUTE, - [ 0 ] = KEY_LIST, // source - [ 19 ] = KEY_INFO, // loop - [ 16 ] = KEY_LAST, // +100 - [ 13 ] = KEY_CLEAR, // reset - [ 12 ] = BTN_RIGHT, // fun++ - [ 4 ] = BTN_LEFT, // fun-- - [ 14 ] = KEY_GOTO, // function - [ 15 ] = KEY_STOP, // freeze + [ 0 ] = KEY_LIST, /* source */ + [ 19 ] = KEY_INFO, /* loop */ + [ 16 ] = KEY_LAST, /* +100 */ + [ 13 ] = KEY_CLEAR, /* reset */ + [ 12 ] = BTN_RIGHT, /* fun++ */ + [ 4 ] = BTN_LEFT, /* fun-- */ + [ 14 ] = KEY_GOTO, /* function */ + [ 15 ] = KEY_STOP, /* freeze */ }; EXPORT_SYMBOL(ir_codes_pixelview); @@ -321,10 +290,6 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, ir->keypressed = 1; ir_input_key_event(dev,ir); } -#if 0 - /* maybe do something like this ??? */ - input_event(a, EV_IR, ir->ir_type, ir->ir_raw); -#endif } /* -------------------------------------------------------------------------- */ -- cgit v1.2.3 From ebe4c6fa535b0410e58e9c8352320896d07e2efb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:53 -0700 Subject: [PATCH] v4l: I2C Miscelaneous - Removed unused structures. - CodingStyle rules applied to comments. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/msp3400.c | 25 ++++--------------------- drivers/media/video/tda7432.c | 13 ------------- drivers/media/video/tda9875.c | 13 ------------- drivers/media/video/tvaudio.c | 5 ----- 4 files changed, 4 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index b4ee9dfe6d4..6239254db27 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -567,10 +567,6 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode) switch (audmode) { case V4L2_TUNER_MODE_STEREO: src = 0x0020 | nicam; -#if 0 - /* spatial effect */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); -#endif break; case V4L2_TUNER_MODE_MONO: if (msp->mode == MSP_MODE_AM_NICAM) { @@ -741,16 +737,14 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { -#if 0 - /* hmm, that one doesn't return on wakeup ... */ - msleep_interruptible(timeout); -#else set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(timeout)); -#endif } } - try_to_freeze(); + if (current->flags & PF_FREEZE) { + refrigerator (); + } + remove_wait_queue(&msp->wq, &wait); return msp->restart; } @@ -1154,17 +1148,10 @@ static int msp3410d_thread(void *data) MSP_CARRIER(10.7)); /* scart routing */ msp3400c_set_scart(client,SCART_IN2,0); -#if 0 - /* radio from SCART_IN2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220); -#else /* msp34xx does radio decoding */ msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020); msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020); -#endif break; case 0x0003: case 0x0004: @@ -1507,10 +1494,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) return -1; } -#if 0 - /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040); -#endif msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance); snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d", diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 07ba6d3ed08..7cb1fb3e66f 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -243,19 +243,6 @@ static int tda7432_write(struct i2c_client *client, int subaddr, int val) } /* I don't think we ever actually _read_ the chip... */ -#if 0 -static int tda7432_read(struct i2c_client *client) -{ - unsigned char buffer; - d2printk("tda7432: In tda7432_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); - return -1; - } - dprintk("tda7432: Read 0x%02x\n", buffer); - return buffer; -} -#endif static int tda7432_set(struct i2c_client *client) { diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 97b113e070f..566e1a5ca13 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -123,19 +123,6 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v return 0; } -#if 0 -static int tda9875_read(struct i2c_client *client) -{ - unsigned char buffer; - dprintk("In tda9875_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9875: I/O error, trying (read)\n"); - return -1; - } - dprintk("Read 0x%02x\n", buffer); - return buffer; -} -#endif static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg) { diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 9a493bea76d..d8b78f1d686 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -864,13 +864,8 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * But changing the mode to VIDEO_SOUND_MONO would switch * external 4052 multiplexer in audio_hook(). */ -#if 0 - if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */ - mode |= VIDEO_SOUND_STEREO; -#else if(nsr & 0x02) /* NSR.S/MB=1 */ mode |= VIDEO_SOUND_STEREO; -#endif if(nsr & 0x01) /* NSR.D/SB=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } else { -- cgit v1.2.3 From f7ce3cc67052de63a29bad90110640b687d12058 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:55 -0700 Subject: [PATCH] v4l: I2C Tuner - Fixed a trouble on tuner-core that generates erros on computers with more than one TV card. - Rename tuner structures fields. - Tail spaces removed. - I2C cleanups and converged to a basic reference structure. - Removed unused structures. - Fix setting frequency on tda8290. - Added code for TEA5767 autodetection. - Standby mode support implemented. It is used to disable a non used tuner. Currenlty implemented on tea5767. - New macro: set_type disables other tuner when changing mode. - Some cleanups. - Use 50 kHz step when tunning radio for most tuners to improve precision. Signed-off-by: Fabien Perrot Signed-off-by: Michael Krufky Signed-off-By: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/mt20xx.c | 16 - drivers/media/video/tda8290.c | 13 +- drivers/media/video/tda9887.c | 9 - drivers/media/video/tea5767.c | 158 +++++---- drivers/media/video/tuner-core.c | 707 +++++++++++++++++++++---------------- drivers/media/video/tuner-simple.c | 85 ++--- 6 files changed, 524 insertions(+), 464 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 9c005cb128d..2fb7c2d1787 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -511,22 +511,6 @@ int microtune_init(struct i2c_client *c) tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", company_code,buf[0x13],buf[0x14]); -#if 0 - /* seems to cause more problems than it solves ... */ - switch (company_code) { - case 0x30bf: - case 0x3cbf: - case 0x3dbf: - case 0x4d54: - case 0x8e81: - case 0x8e91: - /* ok (?) */ - break; - default: - tuner_warn("tuner: microtune: unknown companycode\n"); - return 0; - } -#endif if (buf[0x13] < ARRAY_SIZE(microtune_part) && NULL != microtune_part[buf[0x13]]) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index f59d4601cc6..a8b6a8df510 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,5 @@ /* - * $Id: tda8290.c,v 1.11 2005/06/18 06:09:06 nsh Exp $ + * $Id: tda8290.c,v 1.15 2005/07/08 20:21:33 mchehab Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -136,15 +136,12 @@ static int tda8290_tune(struct i2c_client *c) return 0; } -static void set_frequency(struct tuner *t, u16 ifc) +static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq) { - u32 freq; u32 N; if (t->mode == V4L2_TUNER_RADIO) - freq = t->freq / 1000; - else - freq = t->freq; + freq = freq / 1000; N = (((freq<<3)+ifc)&0x3fffc); @@ -187,14 +184,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); set_audio(t); - set_frequency(t, 864); + set_frequency(t, 864, freq); tda8290_tune(c); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - set_frequency(t, 704); + set_frequency(t, 704, freq); tda8290_tune(c); } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index ee35562f4d1..108c3ad7d62 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -569,15 +569,6 @@ static int tda9887_configure(struct tda9887 *t) tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); -#if 0 - /* This as-is breaks some cards, must be fixed in a - * card-specific way, probably using TDA9887_SET_CONFIG to - * turn on/off port2 */ - if (t->std & V4L2_STD_SECAM_L) { - /* secam fixup (FIXME: move this to tvnorms array?) */ - buf[1] &= ~cOutputPort2Inactive; - } -#endif dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", buf[1],buf[2],buf[3]); diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index a29f08f81f6..b53c748caf2 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -2,7 +2,7 @@ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview * I2C address is allways 0xC0. * - * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $ + * $Id: tea5767.c,v 1.18 2005/07/07 03:02:55 mchehab Exp $ * * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) * This code is placed under the terms of the GNU General Public License @@ -11,23 +11,11 @@ * from their contributions on DScaler. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - +#include +#include +#include #include - -/* Declared at tuner-core.c */ -extern unsigned int tuner_debug; #define PREFIX "TEA5767 " @@ -38,8 +26,8 @@ extern unsigned int tuner_debug; ******************************/ /* First register */ -#define TEA5767_MUTE 0x80 /* Mutes output */ -#define TEA5767_SEARCH 0x40 /* Activates station search */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ /* Bits 0-5 for divider MSB */ /* Second register */ @@ -130,6 +118,14 @@ extern unsigned int tuner_debug; /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff +enum tea5767_xtal_freq { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + + /*****************************************************************************/ static void set_tv_freq(struct i2c_client *c, unsigned int freq) @@ -153,103 +149,112 @@ static void tea5767_status_dump(unsigned char *buffer) else printk(PREFIX "Tuner not at band limit\n"); - div=((buffer[0]&0x3f)<<8) | buffer[1]; + div = ((buffer[0] & 0x3f) << 8) | buffer[1]; switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - frq = 1000*(div*50-700-225)/4; /* Freq in KHz */ + frq = 1000 * (div * 50 - 700 - 225) / 4; /* Freq in KHz */ break; case TEA5767_LOW_LO_13MHz: - frq = 1000*(div*50+700+225)/4; /* Freq in KHz */ + frq = 1000 * (div * 50 + 700 + 225) / 4; /* Freq in KHz */ break; case TEA5767_LOW_LO_32768: - frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */ + frq = 1000 * (div * 32768 / 1000 + 700 + 225) / 4; /* Freq in KHz */ break; case TEA5767_HIGH_LO_32768: default: - frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */ + frq = 1000 * (div * 32768 / 1000 - 700 - 225) / 4; /* Freq in KHz */ break; } - buffer[0] = (div>>8) & 0x3f; - buffer[1] = div & 0xff; + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq/1000,frq%1000,div); + frq / 1000, frq % 1000, div); if (TEA5767_STEREO_MASK & buffer[2]) printk(PREFIX "Stereo\n"); else printk(PREFIX "Mono\n"); - printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK); + printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); - printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4); + printk(PREFIX "ADC Level = %d\n", + (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); - printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK)); + printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); - printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK)); + printk(PREFIX "Reserved = 0x%02x\n", + (buffer[4] & TEA5767_RESERVED_MASK)); } /* Freq should be specifyed at 62.5 Hz */ static void set_radio_freq(struct i2c_client *c, unsigned int frq) { struct tuner *t = i2c_get_clientdata(c); - unsigned char buffer[5]; + unsigned char buffer[5]; unsigned div; int rc; - if ( tuner_debug ) - printk(PREFIX "radio freq counter %d\n",frq); + tuner_dbg (PREFIX "radio freq counter %d\n", frq); /* Rounds freq to next decimal value - for 62.5 KHz step */ /* frq = 20*(frq/16)+radio_frq[frq%16]; */ buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; - buffer[4]=0; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; + buffer[4] = 0; + + if (t->mode == T_STANDBY) { + tuner_dbg("TEA5767 set to standby mode\n"); + buffer[3] |= TEA5767_STDBY; + } if (t->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; - } else - tuner_dbg("TEA5767 set to stereo\n"); + } else { + tuner_dbg("TEA5767 set to stereo\n"); + } - switch (t->type) { + /* Should be replaced */ + switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[4] |= TEA5767_PLLREF_ENABLE; - div = (frq*4/16+700+225+25)/50; + div = (frq * 4 / 16 + 700 + 225 + 25) / 50; break; case TEA5767_LOW_LO_13MHz: - tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); buffer[4] |= TEA5767_PLLREF_ENABLE; - div = (frq*4/16-700-225+25)/50; + div = (frq * 4 / 16 - 700 - 225 + 25) / 50; break; case TEA5767_LOW_LO_32768: - tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); buffer[3] |= TEA5767_XTAL_32768; /* const 700=4000*175 Khz - to adjust freq to right value */ - div = (1000*(frq*4/16-700-225)+16384)>>15; + div = (1000 * (frq * 4 / 16 - 700 - 225) + 16384) >> 15; break; case TEA5767_HIGH_LO_32768: default: - tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[3] |= TEA5767_XTAL_32768; - div = (1000*(frq*4/16+700+225)+16384)>>15; + div = (1000 * (frq * 4 / 16 + 700 + 225) + 16384) >> 15; break; } - buffer[0] = (div>>8) & 0x3f; - buffer[1] = div & 0xff; + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; - if ( tuner_debug ) + if (tuner_debug) tea5767_status_dump(buffer); - if (5 != (rc = i2c_master_send(c,buffer,5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc); + if (5 != (rc = i2c_master_send(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } static int tea5767_signal(struct i2c_client *c) @@ -258,11 +263,11 @@ static int tea5767_signal(struct i2c_client *c) int rc; struct tuner *t = i2c_get_clientdata(c); - memset(buffer,0,sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c,buffer,5))) - tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + memset(buffer, 0, sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4)); + return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4)); } static int tea5767_stereo(struct i2c_client *c) @@ -271,47 +276,46 @@ static int tea5767_stereo(struct i2c_client *c) int rc; struct tuner *t = i2c_get_clientdata(c); - memset(buffer,0,sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c,buffer,5))) - tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + memset(buffer, 0, sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[2] & TEA5767_STEREO_MASK; - if ( tuner_debug ) - tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); - return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0); + return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -int tea_detection(struct i2c_client *c) +int tea5767_autodetection(struct i2c_client *c) { - unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff }; + unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; struct tuner *t = i2c_get_clientdata(c); - if (5 != (rc = i2c_master_recv(c,buffer,5))) { - tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc ); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) { + tuner_warn("it is not a TEA5767. Received %i chars.\n", rc); return EINVAL; } /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ - if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && - buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - tuner_warn ( "All bytes are equal. It is not a TEA5767\n" ); + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + tuner_warn("All bytes are equal. It is not a TEA5767\n"); return EINVAL; } /* Status bytes: * Byte 4: bit 3:1 : CI (Chip Identification) == 0 - * bit 0 : internally set to 0 + * bit 0 : internally set to 0 * Byte 5: bit 7:0 : == 0 */ if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { - tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" ); + tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } - tuner_warn ( "TEA5767 detected.\n" ); + tuner_warn("TEA5767 detected.\n"); return 0; } @@ -319,16 +323,16 @@ int tea5767_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); - if (tea_detection(c)==EINVAL) return EINVAL; + if (tea5767_autodetection(c) == EINVAL) + return EINVAL; - tuner_info("type set to %d (%s)\n", - t->type, TEA5767_TUNER_NAME); - strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); + strlcpy(c->name, "tea5767", sizeof(c->name)); - t->tv_freq = set_tv_freq; + t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = tea5767_signal; - t->is_stereo = tea5767_stereo; + t->is_stereo = tea5767_stereo; return (0); } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6f6bf4a633f..de190630bab 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $ + * $Id: tuner-core.c,v 1.55 2005/07/08 13:20:33 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -23,42 +23,36 @@ #include #include -/* - * comment line bellow to return to old behavor, where only one I2C device is supported - */ - #define UNSET (-1U) /* standard i2c insmod options */ static unsigned short normal_i2c[] = { - 0x4b, /* tda8290 */ + 0x4b, /* tda8290 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, I2C_CLIENT_END }; + I2C_CLIENT_INSMOD; /* insmod options used at init time => read/only */ -static unsigned int addr = 0; +static unsigned int addr = 0; module_param(addr, int, 0444); /* insmod options used at runtime => read/write */ -unsigned int tuner_debug = 0; -module_param(tuner_debug, int, 0644); +unsigned int tuner_debug = 0; +module_param(tuner_debug, int, 0644); -static unsigned int tv_range[2] = { 44, 958 }; +static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; -module_param_array(tv_range, int, NULL, 0644); +module_param_array(tv_range, int, NULL, 0644); module_param_array(radio_range, int, NULL, 0644); MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); -static int this_adap; -static unsigned short first_tuner, tv_tuner, radio_tuner; - static struct i2c_driver driver; static struct i2c_client client_template; @@ -70,18 +64,19 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->tv_freq) { - tuner_info("Huh? tv_set is NULL?\n"); + tuner_warn ("Tuner has no way to set tv freq\n"); return; } - if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16,tv_range[0],tv_range[1]); + if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { + tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", + freq / 16, freq % 16 * 100 / 16, tv_range[0], + tv_range[1]); } - t->tv_freq(c,freq); + t->tv_freq(c, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -89,24 +84,20 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->radio_freq) { - tuner_info("no radio tuning for this one, sorry.\n"); + tuner_warn ("tuner has no way to set radio frequency\n"); return; } - if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) { - if (tuner_debug) - tuner_info("radio freq step 62.5Hz (%d.%06d)\n", - freq/16000,freq%16000*1000/16); - t->radio_freq(c,freq); - } else { - tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); + if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) { + tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", + freq / 16000, freq % 16000 * 100 / 16000, + radio_range[0], radio_range[1]); } + t->radio_freq(c, freq); return; } @@ -117,42 +108,45 @@ static void set_freq(struct i2c_client *c, unsigned long freq) switch (t->mode) { case V4L2_TUNER_RADIO: tuner_dbg("radio freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); - set_radio_freq(c,freq); + freq / 16000, freq % 16000 * 100 / 16000); + set_radio_freq(c, freq); break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: tuner_dbg("tv freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); + freq / 16, freq % 16 * 100 / 16); set_tv_freq(c, freq); break; } t->freq = freq; } -static void set_type(struct i2c_client *c, unsigned int type) +static void set_type(struct i2c_client *c, unsigned int type, + unsigned int new_mode_mask) { struct tuner *t = i2c_get_clientdata(c); unsigned char buffer[4]; - /* sanity check */ - if (type == UNSET || type == TUNER_ABSENT) + if (type == UNSET || type == TUNER_ABSENT) { + tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr); return; - if (type >= tuner_count) + } + + if (type >= tuner_count) { + tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count); return; + } + /* This code detects calls by card attach_inform */ if (NULL == t->i2c.dev.driver) { - /* not registered yet */ - t->type = type; + tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); + + t->type=type; return; } - if ((t->initialized) && (t->type == type)) - /* run only once except type change Hac 04/05*/ - return; - - t->initialized = 1; t->type = type; + switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -161,136 +155,194 @@ static void set_type(struct i2c_client *c, unsigned int type) tda8290_init(c); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT; + if (tea5767_tuner_init(c) == EINVAL) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + t->mode_mask = T_RADIO; break; case TUNER_PHILIPS_FMD1216ME_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; buffer[2] = 0x9c; buffer[3] = 0x60; - i2c_master_send(c,buffer,4); + i2c_master_send(c, buffer, 4); mdelay(1); buffer[2] = 0x86; buffer[3] = 0x54; - i2c_master_send(c,buffer,4); + i2c_master_send(c, buffer, 4); default_tuner_init(c); break; default: - /* TEA5767 autodetection code */ - if (tea5767_tuner_init(c)!=EINVAL) { - t->type = TUNER_TEA5767; - if (first_tuner == 0x60) - first_tuner++; - break; - } - default_tuner_init(c); break; } - tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); + + if (t->mode_mask == T_UNINITIALIZED) + t->mode_mask = new_mode_mask; + + set_freq(c, t->freq); + tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", + c->adapter->name, c->driver->name, c->addr << 1, type, + t->mode_mask); } -#define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ - return 0; } else if (tuner_debug) \ - tuner_info ("Cmd %s accepted to "tun"\n",cmd); -#define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ - CHECK_ADDR(radio_tuner,cmd,"radio") } else \ - { CHECK_ADDR(tv_tuner,cmd,"TV"); } +/* + * This function apply tuner config to tuner specified + * by tun_setup structure. I addr is unset, then admin status + * and tun addr status is more precise then current status, + * it's applied. Otherwise status and type are applied only to + * tuner with exactly the same addr. +*/ + +static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (tun_setup->addr == ADDR_UNSET) { + if (t->mode_mask & tun_setup->mode_mask) + set_type(c, tun_setup->type, tun_setup->mode_mask); + } else if (tun_setup->addr == c->addr) { + set_type(c, tun_setup->type, tun_setup->mode_mask); + } +} -static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) +static inline int check_mode(struct tuner *t, char *cmd) { - /* ADDR_UNSET defaults to first available tuner */ - if ( tun_addr->addr == ADDR_UNSET ) { - if (first_tuner != c->addr) - return; - switch (tun_addr->v4l2_tuner) { + if (1 << t->mode & t->mode_mask) { + switch (t->mode) { case V4L2_TUNER_RADIO: - radio_tuner=c->addr; + tuner_dbg("Cmd %s accepted for radio\n", cmd); break; - default: - tv_tuner=c->addr; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); break; } - } else { - /* Sets tuner to its configured value */ - switch (tun_addr->v4l2_tuner) { - case V4L2_TUNER_RADIO: - radio_tuner=tun_addr->addr; - if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type); - return; - default: - tv_tuner=tun_addr->addr; - if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type); - return; - } + return 0; } - set_type(c,tun_addr->type); + return EINVAL; } static char pal[] = "-"; module_param_string(pal, pal, sizeof(pal), 0644); +static char secam[] = "-"; +module_param_string(secam, secam, sizeof(secam), 0644); +/* get more precise norm info from insmod option */ static int tuner_fixup_std(struct tuner *t) { if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { - /* get more precise norm info from insmod option */ switch (pal[0]) { case 'b': case 'B': case 'g': case 'G': - tuner_dbg("insmod fixup: PAL => PAL-BG\n"); + tuner_dbg ("insmod fixup: PAL => PAL-BG\n"); t->std = V4L2_STD_PAL_BG; break; case 'i': case 'I': - tuner_dbg("insmod fixup: PAL => PAL-I\n"); + tuner_dbg ("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: PAL => PAL-DK\n"); + tuner_dbg ("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case 'M': + case 'm': + tuner_dbg ("insmod fixup: PAL => PAL-M\n"); + t->std = V4L2_STD_PAL_M; + break; + case 'N': + case 'n': + tuner_dbg ("insmod fixup: PAL => PAL-N\n"); + t->std = V4L2_STD_PAL_N; + break; } } + if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + switch (secam[0]) { + case 'd': + case 'D': + case 'k': + case 'K': + tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n"); + t->std = V4L2_STD_SECAM_DK; + break; + case 'l': + case 'L': + tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); + t->std = V4L2_STD_SECAM_L; + break; + } + } + return 0; } /* ---------------------------------------------------------------------- */ +/* static var Used only in tuner_attach and tuner_probe */ +static unsigned default_mode_mask; + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_attach. + */ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct tuner *t; - /* by default, first I2C card is both tv and radio tuner */ - if (this_adap == 0) { - first_tuner = addr; - tv_tuner = addr; - radio_tuner = addr; - } - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; + client_template.adapter = adap; + client_template.addr = addr; - t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memset(t,0,sizeof(struct tuner)); - memcpy(&t->i2c,&client_template,sizeof(struct i2c_client)); + t = kmalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + memset(t, 0, sizeof(struct tuner)); + memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(&t->i2c, t); - t->type = UNSET; - t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ - t->audmode = V4L2_TUNER_MODE_STEREO; + t->type = UNSET; + t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + + tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + + /* TEA5767 autodetection code - only for addr = 0xc0 */ + if (addr == 0x60) { + if (tea5767_autodetection(&t->i2c) != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->freq = 87.5 * 16; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + i2c_attach_client (&t->i2c); + set_type(&t->i2c,t->type, t->mode_mask); + return 0; + } + } - i2c_attach_client(&t->i2c); - tuner_info("chip found @ 0x%x (%s)\n", - addr << 1, adap->name); + /* Initializes only the first adapter found */ + if (default_mode_mask != T_UNINITIALIZED) { + tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); + t->mode_mask = default_mode_mask; + t->freq = 400 * 16; /* Sets freq to VHF High */ + default_mode_mask = T_UNINITIALIZED; + } - set_type(&t->i2c, t->type); + /* Should be just before return */ + i2c_attach_client (&t->i2c); + set_type (&t->i2c,t->type, t->mode_mask); return 0; } @@ -300,11 +352,8 @@ static int tuner_probe(struct i2c_adapter *adap) normal_i2c[0] = addr; normal_i2c[1] = I2C_CLIENT_END; } - this_adap = 0; - first_tuner = 0; - tv_tuner = 0; - radio_tuner = 0; + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); @@ -316,9 +365,10 @@ static int tuner_detach(struct i2c_client *client) struct tuner *t = i2c_get_clientdata(client); int err; - err=i2c_detach_client(&t->i2c); + err = i2c_detach_client(&t->i2c); if (err) { - tuner_warn ("Client deregistration failed, client not detached.\n"); + tuner_warn + ("Client deregistration failed, client not detached.\n"); return err; } @@ -326,37 +376,65 @@ static int tuner_detach(struct i2c_client *client) return 0; } -#define SWITCH_V4L2 if (!t->using_v4l2 && tuner_debug) \ - tuner_info("switching to v4l2\n"); \ - t->using_v4l2 = 1; -#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \ - tuner_info("ignore v4l1 call\n"); \ - return 0; } +/* + * Switch tuner to other mode. If tuner support both tv and radio, + * set another frequency to some value (This is needed for some pal + * tuners to avoid locking). Otherwise, just put second tuner in + * standby mode. + */ + +static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) +{ + if (mode != t->mode) { + + t->mode = mode; + if (check_mode(t, cmd) == EINVAL) { + t->mode = T_STANDBY; + if (V4L2_TUNER_RADIO == mode) { + set_tv_freq(client, 400 * 16); + } else { + set_radio_freq(client, 87.5 * 16000); + } + return EINVAL; + } + } + return 0; +} + +#define switch_v4l2() if (!t->using_v4l2) \ + tuner_dbg("switching to v4l2\n"); \ + t->using_v4l2 = 1; + +static inline int check_v4l2(struct tuner *t) +{ + if (t->using_v4l2) { + tuner_dbg ("ignore v4l1 call\n"); + return EINVAL; + } + return 0; +} -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); - unsigned int *iarg = (int*)arg; + unsigned int *iarg = (int *)arg; - switch (cmd) { + switch (cmd) { /* --- configuration --- */ - case TUNER_SET_TYPE: - set_type(client,*iarg); - break; case TUNER_SET_TYPE_ADDR: - set_addr(client,(struct tuner_addr *)arg); + tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", + ((struct tuner_setup *)arg)->type, + ((struct tuner_setup *)arg)->addr, + ((struct tuner_setup *)arg)->mode_mask); + + set_addr(client, (struct tuner_setup *)arg); break; case AUDC_SET_RADIO: - t->mode = V4L2_TUNER_RADIO; - CHECK_ADDR(tv_tuner,"AUDC_SET_RADIO","TV"); - - if (V4L2_TUNER_RADIO != t->mode) { - set_tv_freq(client,400 * 16); - } + set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); break; case AUDC_CONFIG_PINNACLE: - CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE","TV"); + if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL) + return 0; switch (*iarg) { case 2: tuner_dbg("pinnacle pal\n"); @@ -368,219 +446,238 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } break; + case TDA9887_SET_CONFIG: + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ case VIDIOCSCHAN: - { - static const v4l2_std_id map[] = { - [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, - [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, - [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, - [ 4 /* bttv */ ] = V4L2_STD_PAL_M, - [ 5 /* bttv */ ] = V4L2_STD_PAL_N, - [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, - }; - struct video_channel *vc = arg; - - CHECK_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - CHECK_ADDR(tv_tuner,"VIDIOCSCHAN","TV"); - - if (vc->norm < ARRAY_SIZE(map)) - t->std = map[vc->norm]; - tuner_fixup_std(t); - if (t->freq) - set_tv_freq(client,t->freq); - return 0; - } + { + static const v4l2_std_id map[] = { + [VIDEO_MODE_PAL] = V4L2_STD_PAL, + [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M, + [VIDEO_MODE_SECAM] = V4L2_STD_SECAM, + [4 /* bttv */ ] = V4L2_STD_PAL_M, + [5 /* bttv */ ] = V4L2_STD_PAL_N, + [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, + }; + struct video_channel *vc = arg; + + if (check_v4l2(t) == EINVAL) + return 0; + + if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL) + return 0; + + if (vc->norm < ARRAY_SIZE(map)) + t->std = map[vc->norm]; + tuner_fixup_std(t); + if (t->freq) + set_tv_freq(client, t->freq); + return 0; + } case VIDIOCSFREQ: - { - unsigned long *v = arg; + { + unsigned long *v = arg; - CHECK_MODE("VIDIOCSFREQ"); - CHECK_V4L2; - set_freq(client,*v); - return 0; - } + if (check_mode(t, "VIDIOCSFREQ") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + set_freq(client, *v); + return 0; + } case VIDIOCGTUNER: - { - struct video_tuner *vt = arg; - - CHECK_ADDR(radio_tuner,"VIDIOCGTUNER","radio"); - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - vt->signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) - vt->flags |= VIDEO_TUNER_STEREO_ON; - else - vt->flags &= ~VIDEO_TUNER_STEREO_ON; - } - vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ + { + struct video_tuner *vt = arg; + + if (check_mode(t, "VIDIOCGTUNER") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + if (V4L2_TUNER_RADIO == t->mode) { + if (t->has_signal) + vt->signal = t->has_signal(client); + if (t->is_stereo) { + if (t->is_stereo(client)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ - vt->rangelow = radio_range[0] * 16000; - vt->rangehigh = radio_range[1] * 16000; + vt->rangelow = radio_range[0] * 16000; + vt->rangehigh = radio_range[1] * 16000; - } else { - vt->rangelow = tv_range[0] * 16; - vt->rangehigh = tv_range[1] * 16; - } + } else { + vt->rangelow = tv_range[0] * 16; + vt->rangehigh = tv_range[1] * 16; + } - return 0; - } + return 0; + } case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO","radio"); - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) - va->mode = t->is_stereo(client) - ? VIDEO_SOUND_STEREO - : VIDEO_SOUND_MONO; - return 0; - } + { + struct video_audio *va = arg; + + if (check_mode(t, "VIDIOCGAUDIO") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) + va->mode = t->is_stereo(client) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + return 0; + } case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; + { + v4l2_std_id *id = arg; - SWITCH_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - CHECK_ADDR(tv_tuner,"VIDIOC_S_STD","TV"); + if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") + == EINVAL) + return 0; - t->std = *id; - tuner_fixup_std(t); - if (t->freq) - set_freq(client,t->freq); - break; - } + switch_v4l2(); + + t->std = *id; + tuner_fixup_std(t); + if (t->freq) + set_freq(client, t->freq); + break; + } case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - CHECK_MODE("VIDIOC_S_FREQUENCY"); - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == f->type && - V4L2_TUNER_RADIO != t->mode) - set_tv_freq(client,400*16); - t->mode = f->type; - set_freq(client,f->frequency); - break; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + { + struct v4l2_frequency *f = arg; + + t->freq = f->frequency; + switch_v4l2(); + if (V4L2_TUNER_RADIO == f->type && + V4L2_TUNER_RADIO != t->mode) { + if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") + == EINVAL) + return 0; + } + set_freq(client,t->freq); - CHECK_MODE("VIDIOC_G_FREQUENCY"); - SWITCH_V4L2; - f->type = t->mode; - f->frequency = t->freq; - break; - } + break; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL) + return 0; + switch_v4l2(); + f->type = t->mode; + f->frequency = t->freq; + break; + } case VIDIOC_G_TUNER: - { - struct v4l2_tuner *tuner = arg; - - CHECK_MODE("VIDIOC_G_TUNER"); - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - tuner -> signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) { - tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - } else { - tuner -> rxsubchans = V4L2_TUNER_SUB_MONO; + { + struct v4l2_tuner *tuner = arg; + + if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL) + return 0; + switch_v4l2(); + + if (V4L2_TUNER_RADIO == t->mode) { + + if (t->has_signal) + tuner->signal = t->has_signal(client); + + if (t->is_stereo) { + if (t->is_stereo(client)) { + tuner->rxsubchans = + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_MONO; + } else { + tuner->rxsubchans = + V4L2_TUNER_SUB_MONO; + } } + + tuner->capability |= + V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + + tuner->audmode = t->audmode; + + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; + } else { + tuner->rangelow = tv_range[0] * 16; + tuner->rangehigh = tv_range[1] * 16; } - tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - tuner->audmode = t->audmode; - - tuner->rangelow = radio_range[0] * 16000; - tuner->rangehigh = radio_range[1] * 16000; - } else { - tuner->rangelow = tv_range[0] * 16; - tuner->rangehigh = tv_range[1] * 16; + break; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *tuner = arg; + + if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL) + return 0; + + switch_v4l2(); + + if (V4L2_TUNER_RADIO == t->mode) { + t->audmode = tuner->audmode; + set_radio_freq(client, t->freq); + } + break; } - break; - } - case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ - { - struct v4l2_tuner *tuner = arg; - - CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio"); - SWITCH_V4L2; - - /* To switch the audio mode, applications initialize the - index and audmode fields and the reserved array and - call the VIDIOC_S_TUNER ioctl. */ - /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, - V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, - V4L2_TUNER_MODE_SAP */ - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) - t->audmode = V4L2_TUNER_MODE_MONO; - else - t->audmode = V4L2_TUNER_MODE_STEREO; - - set_radio_freq(client, t->freq); - break; - } - case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ - break; default: - tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); - /* nothing */ + tuner_dbg("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); break; } return 0; } -static int tuner_suspend(struct device * dev, u32 state, u32 level) +static int tuner_suspend(struct device *dev, u32 state, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("suspend\n"); + tuner_dbg ("suspend\n"); /* FIXME: power down ??? */ return 0; } -static int tuner_resume(struct device * dev, u32 level) +static int tuner_resume(struct device *dev, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("resume\n"); + tuner_dbg ("resume\n"); if (t->freq) - set_freq(c,t->freq); + set_freq(c, t->freq); return 0; } /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "tuner", - .id = I2C_DRIVERID_TUNER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command, + .owner = THIS_MODULE, + .name = "tuner", + .id = I2C_DRIVERID_TUNER, + .flags = I2C_DF_NOTIFY, + .attach_adapter = tuner_probe, + .detach_client = tuner_detach, + .command = tuner_command, .driver = { - .suspend = tuner_suspend, - .resume = tuner_resume, - }, + .suspend = tuner_suspend, + .resume = tuner_resume, + }, }; -static struct i2c_client client_template = -{ +static struct i2c_client client_template = { I2C_DEVNAME("(tuner unset)"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; static int __init tuner_init_module(void) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index c39ed6226ee..a3f8e83f531 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-simple.c,v 1.31 2005/06/21 16:02:25 mkrufky Exp $ + * $Id: tuner-simple.c,v 1.39 2005/07/07 01:49:30 mkrufky Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -54,6 +54,27 @@ #define PHILIPS_MF_SET_PAL_L 0x03 // France #define PHILIPS_MF_SET_PAL_L2 0x02 // L' +/* Control byte */ + +#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ +#define TUNER_RATIO_SELECT_50 0x00 +#define TUNER_RATIO_SELECT_32 0x02 +#define TUNER_RATIO_SELECT_166 0x04 +#define TUNER_RATIO_SELECT_62 0x06 + +#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ + +/* Status byte */ + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 +#define TUNER_SIGNAL 0x07 +#define TUNER_STEREO 0x10 + +#define TUNER_PLL_LOCKED 0x40 +#define TUNER_STEREO_MK3 0x04 /* ---------------------------------------------------------------------- */ @@ -211,21 +232,17 @@ static struct tunertype tuners[] = { 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, { "Philips FQ1236A MK4", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - - /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */ - { "Ymec TVision TVF-8531MF", Philips, NTSC, + { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, + { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - /* Should work for TNF9533-D/IF, TNF9533-B/DF */ - { "Tena TNF9533-D/IF", Philips, PAL, + { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - - /* This entry is for TEA5767 FM radio only chip used on several boards w/TV tuner */ - { TEA5767_TUNER_NAME, Philips, RADIO, - -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + { "Philips TEA5767HN FM Radio", Philips, RADIO, + /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, }; @@ -244,15 +261,6 @@ static int tuner_getstatus(struct i2c_client *c) return byte; } -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 - -#define TUNER_STEREO 0x10 /* radio mode */ -#define TUNER_STEREO_MK3 0x04 /* radio mode */ -#define TUNER_SIGNAL 0x07 /* radio mode */ - static int tuner_signal(struct i2c_client *c) { return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; @@ -278,22 +286,6 @@ static int tuner_stereo(struct i2c_client *c) return stereo; } -#if 0 /* unused */ -static int tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_FL); -} - -static int tuner_afcstatus (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_AFC) - 2; -} - -static int tuner_mode (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_MODE) >> 3; -} -#endif /* ---------------------------------------------------------------------- */ @@ -376,7 +368,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) case TUNER_MICROTUNE_4042FI5: /* Set the charge pump for fast tuning */ - tun->config |= 0x40; + tun->config |= TUNER_CHARGE_PUMP; break; } @@ -425,14 +417,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; } - /* bit 6 is PLL locked indicator */ - if (status_byte & 0x40) + if (status_byte & TUNER_PLL_LOCKED) break; udelay(10); } /* Set the charge pump for optimized phase noise figure */ - tun->config &= ~0x40; + tun->config &= ~TUNER_CHARGE_PUMP; buffer[0] = (div>>8) & 0x7f; buffer[1] = div & 0xff; buffer[2] = tun->config; @@ -453,26 +444,22 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) unsigned div; int rc; - tun=&tuners[t->type]; - div = (freq / 1000) + (int)(16*10.7); - buffer[2] = tun->config; + tun = &tuners[t->type]; + div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ + buffer[2] = (tun->config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - /*These values are empirically determinated */ - div = (freq * 122) / 16000 - 20; - buffer[2] = 0x88; /* could be also 0x80 */ - buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */ - break; + tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + 333 * 2; - buffer[2] = 0x80; + div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ buffer[3] = 0x19; break; case TUNER_LG_PAL_FM: -- cgit v1.2.3 From 1455050f04084161c8a9425008e3b9b5f5c4c2a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:57 -0700 Subject: [PATCH] v4l: drivers/media/video/Kconfig - Removed obsolete option. Current code needs multi tuner. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/Kconfig | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e771064689e..f461750c764 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -7,19 +7,6 @@ menu "Video For Linux" comment "Video Adapters" -config TUNER_MULTI_I2C - bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)" - depends on VIDEO_DEV && EXPERIMENTAL - ---help--- - Some video adapters have more than one tuner inside. This patch - enables support for using more than one tuner. This is required - for some cards to allow tunning both video and radio. - It also improves I2C autodetection for these cards. - - Only few tuners currently is supporting this. More to come. - - It is safe to say 'Y' here even if your card has only one I2C tuner. - config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C -- cgit v1.2.3 From 85369df350b138f26eac779da33de0960635ca4d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:59 -0700 Subject: [PATCH] v4l: MXB fix to correct tuner ioctl - driver command adapted to use new control (TUNER_SET_TYPE_ADDR, instead of TUNER_SET_TYPE) Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/mxb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 70bf1f1fad5..486234d41b5 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -326,6 +326,7 @@ static int mxb_init_done(struct saa7146_dev* dev) struct mxb* mxb = (struct mxb*)dev->ext_priv; struct video_decoder_init init; struct i2c_msg msg; + struct tuner_setup tun_setup; int i = 0, err = 0; struct tea6415c_multiplex vm; @@ -349,8 +350,10 @@ static int mxb_init_done(struct saa7146_dev* dev) mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i); /* select a tuner type */ - i = 5; - mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE, &i); + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.addr = ADDR_UNSET; + tun_setup.type = 5; + mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup); /* mute audio on tea6420s */ mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]); -- cgit v1.2.3 From 330a115ae46e7d7b5fe2d4e506ba8ae2e0027143 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:01 -0700 Subject: [PATCH] v4l: SAA7134 Update - Corrected all cards marked as 7135 cards to 7133. - Add new card support for Compro VideoMate TV Gold+II. - Add new card support for Kworld Xpert TV PVR7134 - Add new card support for Typhoon DVB-T Cardbus. - Changes to comply with CodingStyle: // comments converted to /* */ - Remove irq2_mask field from saa7134_dev structure. - Collect all the bits needed in saa7134_hwinit2() instead. - Distinguish the different variants of the Medion MD7134 modules via eeprom - moved Philips FMD1216 radio specific setup to saa7134-core.c - Fix kernel compile error with CONFIG_MODULES=n - Cleanup tuner private calls. - Some Indent fixes. Signed-off-by: Michael Tokarev Signed-off-by: Michael Krufky Signed-off-by: Hannibal Signed-off-by: Elshin Roman Signed-off-by: Hermann Pitton Signed-off-by: Juergen Orschiedt Signed-off-by: Hartmut Hackmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa7134-cards.c | 2174 +++++++++++++++---------- drivers/media/video/saa7134/saa7134-core.c | 74 +- drivers/media/video/saa7134/saa7134-i2c.c | 45 +- drivers/media/video/saa7134/saa7134-input.c | 48 +- drivers/media/video/saa7134/saa7134-oss.c | 19 +- drivers/media/video/saa7134/saa7134-ts.c | 6 +- drivers/media/video/saa7134/saa7134-tvaudio.c | 121 +- drivers/media/video/saa7134/saa7134-vbi.c | 12 - drivers/media/video/saa7134/saa7134-video.c | 54 +- drivers/media/video/saa7134/saa7134.h | 21 +- 10 files changed, 1498 insertions(+), 1076 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0c781e24c44..88b71a20b60 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1,6 +1,5 @@ - /* - * $Id: saa7134-cards.c,v 1.58 2005/06/07 18:05:00 nsh Exp $ + * $Id: saa7134-cards.c,v 1.80 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * card-specific stuff. @@ -47,6 +46,10 @@ struct saa7134_board saa7134_boards[] = { .name = "UNKNOWN/GENERIC", .audio_clock = 0x00187de7, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = "default", .vmux = 0, @@ -58,6 +61,10 @@ struct saa7134_board saa7134_boards[] = { .name = "Proteus Pro [philips reference design]", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 0, @@ -83,6 +90,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyVIDEO3000", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -90,7 +101,7 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .gpio = 0x8000, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -117,12 +128,21 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x2000, }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x8000, + }, }, [SAA7134_BOARD_FLYVIDEO2000] = { /* "TC Wan" */ .name = "LifeView FlyVIDEO2000", .audio_clock = 0x00200000, .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -146,14 +166,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x4000, }}, - .radio = { - .name = name_radio, - .amux = LINE2, + .radio = { + .name = name_radio, + .amux = LINE2, .gpio = 0x2000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x8000, }, }, @@ -162,6 +182,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyTV Platinum Mini", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_tv, .vmux = 1, @@ -183,6 +207,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyTV Platinum FM", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */ .inputs = {{ .name = name_tv, @@ -190,7 +218,7 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .gpio = 0x10000, /* GP16=1 selects TV input */ .tv = 1, - },{ + },{ /* .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -200,29 +228,38 @@ struct saa7134_board saa7134_boards[] = { */ .name = name_comp1, /* Composite signal on S-Video input */ .vmux = 0, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ },{ .name = name_comp2, /* Composite input */ .vmux = 3, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ },{ .name = name_svideo, /* S-Video signal on S-Video input */ .vmux = 8, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ }}, .radio = { .name = name_radio, .amux = TV, .gpio = 0x00000, /* GP16=0 selects FM radio antenna */ }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x10000, + }, }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 0, @@ -245,33 +282,40 @@ struct saa7134_board saa7134_boards[] = { .video_out = CCIR656, }, [SAA7134_BOARD_MONSTERTV] = { - /* "K.Ohta" */ - .name = "SKNet Monster TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, + /* "K.Ohta" */ + .name = "SKNet Monster TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, }, [SAA7134_BOARD_MD9717] = { .name = "Tevion MD 9717", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, @@ -302,10 +346,13 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_TVSTATION_RDS] = { - /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ + /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -314,10 +361,10 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, },{ .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ .name = name_svideo, .vmux = 8, @@ -328,10 +375,10 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, + .name = "CVid over SVid", + .vmux = 0, + .amux = LINE1, + }}, .radio = { .name = name_radio, .amux = LINE2, @@ -341,6 +388,9 @@ struct saa7134_board saa7134_boards[] = { .name = "KNC One TV-Station DVR", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x820000, .inputs = {{ @@ -369,32 +419,38 @@ struct saa7134_board saa7134_boards[] = { .video_out = CCIR656, }, [SAA7134_BOARD_CINERGY400] = { - .name = "Terratec Cinergy 400 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }} - }, + .name = "Terratec Cinergy 400 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }} + }, [SAA7134_BOARD_MD5044] = { .name = "Medion 5044", - .audio_clock = 0x00187de7, // was: 0x00200000, + .audio_clock = 0x00187de7, /* was: 0x00200000, */ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -426,57 +482,65 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_KWORLD] = { - .name = "Kworld/KuroutoShikou SAA7130-TVPCI", + .name = "Kworld/KuroutoShikou SAA7130-TVPCI", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + }, [SAA7134_BOARD_CINERGY600] = { - .name = "Terratec Cinergy 600 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + .name = "Terratec Cinergy 600 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }}, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }}, .radio = { .name = name_radio, .amux = LINE2, - }, - }, + }, + }, [SAA7134_BOARD_MD7134] = { .name = "Medion 7134", - //.audio_clock = 0x00200000, .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -504,6 +568,9 @@ struct saa7134_board saa7134_boards[] = { .name = "Typhoon TV+Radio 90031", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -523,11 +590,14 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, - }, + }, [SAA7134_BOARD_ELSA] = { .name = "ELSA EX-VISION 300TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_HITACHI_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_svideo, .vmux = 8, @@ -542,11 +612,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, }}, - }, + }, [SAA7134_BOARD_ELSA_500TV] = { .name = "ELSA EX-VISION 500TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_HITACHI_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_svideo, .vmux = 7, @@ -562,83 +635,100 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, }}, - }, + }, [SAA7134_BOARD_ASUSTeK_TVFM7134] = { - .name = "ASUS TV-FM 7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7135_BOARD_ASUSTeK_TVFM7135] = { - .name = "ASUS TV-FM 7135", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, + .name = "ASUS TV-FM 7134", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_ASUSTeK_TVFM7135] = { + .name = "ASUS TV-FM 7135", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, .gpio = 0x0000, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, .gpio = 0x0000, - }}, - .radio = { - .name = name_radio, - .amux = TV, + }}, + .radio = { + .name = name_radio, + .amux = TV, .gpio = 0x200000, - }, + }, + .mute = { + .name = name_mute, + .gpio = 0x0000, + }, + }, [SAA7134_BOARD_VA1000POWER] = { - .name = "AOPEN VA1000 POWER", + .name = "AOPEN VA1000 POWER", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, }, [SAA7134_BOARD_10MOONSTVMASTER] = { /* "lilicheng" */ .name = "10MOONS PCI TV CAPTURE CARD", .audio_clock = 0x00200000, .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -662,14 +752,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x4000, }}, - .radio = { - .name = name_radio, - .amux = LINE2, + .radio = { + .name = name_radio, + .amux = LINE2, .gpio = 0x2000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x8000, }, }, @@ -678,6 +768,9 @@ struct saa7134_board saa7134_boards[] = { .name = "BMK MPEX No Tuner", .audio_clock = 0x200000, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 4, @@ -706,80 +799,94 @@ struct saa7134_board saa7134_boards[] = { .name = "Compro VideoMate TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { .name = "Compro VideoMate TV Gold+", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, .gpiomask = 0x800c0000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x06c00012, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x0ac20012, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x08c20012, - .tv = 1, - }}, - }, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x06c00012, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x0ac20012, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x08c20012, + .tv = 1, + }}, /* radio and probably mute is missing */ + }, [SAA7134_BOARD_CRONOS_PLUS] = { - /* gpio pins: - 0 .. 3 BASE_ID - 4 .. 7 PROTECT_ID - 8 .. 11 USER_OUT - 12 .. 13 USER_IN - 14 .. 15 VIDIN_SEL */ + /* + gpio pins: + 0 .. 3 BASE_ID + 4 .. 7 PROTECT_ID + 8 .. 11 USER_OUT + 12 .. 13 USER_IN + 14 .. 15 VIDIN_SEL + */ .name = "Matrox CronosPlus", .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0xcf00, - .inputs = {{ - .name = name_comp1, - .vmux = 0, + .inputs = {{ + .name = name_comp1, + .vmux = 0, .gpio = 2 << 14, },{ - .name = name_comp2, - .vmux = 0, + .name = name_comp2, + .vmux = 0, .gpio = 1 << 14, },{ - .name = name_comp3, - .vmux = 0, + .name = name_comp3, + .vmux = 0, .gpio = 0 << 14, },{ - .name = name_comp4, - .vmux = 0, + .name = name_comp4, + .vmux = 0, .gpio = 3 << 14, },{ .name = name_svideo, .vmux = 8, .gpio = 2 << 14, - }}, - }, + }}, + }, [SAA7134_BOARD_MD2819] = { .name = "AverMedia M156 / Medion 2819", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -809,6 +916,9 @@ struct saa7134_board saa7134_boards[] = { .name = "BMK MPEX Tuner", .audio_clock = 0x200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 1, @@ -825,88 +935,101 @@ struct saa7134_board saa7134_boards[] = { }}, .mpeg = SAA7134_MPEG_EMPRESS, .video_out = CCIR656, - }, - [SAA7134_BOARD_ASUSTEK_TVFM7133] = { - .name = "ASUS TV-FM 7133", - .audio_clock = 0x00187de7, - // probably wrong, the 7133 one is the NTSC version ... - // .tuner_type = TUNER_PHILIPS_FM1236_MK3 - .tuner_type = TUNER_LG_NTSC_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { - .name = "Pinnacle PCTV Stereo (saa7134)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_MANLI_MTV002] = { - /* Ognjen Nastic */ - .name = "Manli MuchTV M-TV002/Behold TV 403 FM", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + }, + [SAA7134_BOARD_ASUSTEK_TVFM7133] = { + .name = "ASUS TV-FM 7133", + .audio_clock = 0x00187de7, + /* probably wrong, the 7133 one is the NTSC version ... + * .tuner_type = TUNER_PHILIPS_FM1236_MK3 */ + .tuner_type = TUNER_LG_NTSC_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, + .name = name_comp1, + .vmux = 4, + .amux = LINE2, },{ - .name = name_tv, - .vmux = 3, + .name = name_svideo, + .vmux = 6, .amux = LINE2, - .tv = 1, }}, .radio = { .name = name_radio, - .amux = LINE2, + .amux = LINE1, }, }, - [SAA7134_BOARD_MANLI_MTV001] = { - /* Ognjen Nastic UNTESTED */ - .name = "Manli MuchTV M-TV001/Behold TV 401", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { + .name = "Pinnacle PCTV Stereo (saa7134)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, .inputs = {{ - .name = name_svideo, + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_MANLI_MTV002] = { + /* Ognjen Nastic */ + .name = "Manli MuchTV M-TV002/Behold TV 403 FM", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_MANLI_MTV001] = { + /* Ognjen Nastic UNTESTED */ + .name = "Manli MuchTV M-TV001/Behold TV 401", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, .vmux = 8, .amux = LINE1, },{ @@ -921,14 +1044,17 @@ struct saa7134_board saa7134_boards[] = { }}, .mute = { .name = name_mute, - .amux = LINE1, + .amux = LINE1, }, - }, + }, [SAA7134_BOARD_TG3000TV] = { /* TransGear 3000TV */ .name = "Nagase Sangyo TransGear 3000TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, @@ -944,81 +1070,90 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, }, - [SAA7134_BOARD_ECS_TVP3XP] = { - .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", - .audio_clock = 0x187de7, // xtal 32.1 MHz - .tuner_type = TUNER_PHILIPS_PAL, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + [SAA7134_BOARD_ECS_TVP3XP] = { + .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", + .audio_clock = 0x187de7, /* xtal 32.1 MHz */ + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = "CVid over SVid", + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { + .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", + .audio_clock = 0x187de7, + .tuner_type = TUNER_PHILIPS_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, },{ .name = "CVid over SVid", .vmux = 0, .amux = LINE1, }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { - .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, [SAA7134_BOARD_AVACSSMARTTV] = { /* Roman Pszonczenko */ .name = "AVACS SmartTV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -1047,6 +1182,9 @@ struct saa7134_board saa7134_boards[] = { .name = "AVerMedia DVD EZMaker", .audio_clock = 0x00187de7, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 3, @@ -1055,28 +1193,34 @@ struct saa7134_board saa7134_boards[] = { .vmux = 8, }}, }, - [SAA7134_BOARD_NOVAC_PRIMETV7133] = { - /* toshii@netbsd.org */ - .name = "Noval Prime TV 7133", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ALPS_TSBH1_NTSC, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - }}, - }, + [SAA7134_BOARD_NOVAC_PRIMETV7133] = { + /* toshii@netbsd.org */ + .name = "Noval Prime TV 7133", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ALPS_TSBH1_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_comp1, + .vmux = 3, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 8, + }}, + }, [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = { .name = "AverMedia AverTV Studio 305", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1256_IH3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -1097,35 +1241,41 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, .radio = { - .name = name_radio, - .amux = LINE2, - }, + .name = name_radio, + .amux = LINE2, + }, .mute = { - .name = name_mute, - .amux = LINE1, + .name = name_mute, + .amux = LINE1, }, }, - [SAA7133_BOARD_UPMOST_PURPLE_TV] = { - .name = "UPMOST PURPLE TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 7, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 7, - .amux = LINE1, - }}, + [SAA7134_BOARD_UPMOST_PURPLE_TV] = { + .name = "UPMOST PURPLE TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 7, + .amux = TV, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 7, + .amux = LINE1, + }}, }, [SAA7134_BOARD_ITEMS_MTV005] = { /* Norman Jonas */ .name = "Items MuchTV Plus / IT-005", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 3, @@ -1149,27 +1299,30 @@ struct saa7134_board saa7134_boards[] = { .name = "Terratec Cinergy 200 TV", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ - .name = name_tv, + .name = name_tv, .vmux = 1, .amux = LINE2, .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, }}, .mute = { - .name = name_mute, - .amux = LINE2, + .name = name_mute, + .amux = LINE2, }, }, [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { @@ -1177,84 +1330,96 @@ struct saa7134_board saa7134_boards[] = { .name = "Compro VideoMate TV PVR/FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x808c0080, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, .gpio = 0x00080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, .gpio = 0x00080, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2_LEFT, - .tv = 1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2_LEFT, + .tv = 1, .gpio = 0x00080, - }}, + }}, .radio = { .name = name_radio, .amux = LINE2, .gpio = 0x80000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x40000, }, - }, - [SAA7134_BOARD_SABRENT_SBTTVFM] = { + }, + [SAA7134_BOARD_SABRENT_SBTTVFM] = { /* Michael Rodriguez-Torrent */ - .name = "Sabrent SBT-TVFM (saa7130)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ + .name = "Sabrent SBT-TVFM (saa7130)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 1, .amux = LINE2, },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, [SAA7134_BOARD_ZOLID_XPERT_TV7134] = { /* Helge Jensen */ - .name = ":Zolid Xpert TV7134", + .name = ":Zolid Xpert TV7134", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, }, [SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = { /* "Matteo Az" ;-) */ .name = "Empire PCI TV-Radio LE", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x4000, .inputs = {{ .name = name_tv_mono, @@ -1273,18 +1438,18 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x8000, }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x8000, - }, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x8000, + }, .mute = { - .name = name_mute, - .amux = TV, - .gpio =0x8000, - } + .name = name_mute, + .amux = TV, + .gpio =0x8000, + } }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = { + [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = { /* Nickolay V. Shmyrev Lots of thanks to Andrey Zolotarev @@ -1292,6 +1457,9 @@ struct saa7134_board saa7134_boards[] = { .name = "Avermedia AVerTV Studio 307", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1256_IH3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x03, .inputs = {{ @@ -1321,13 +1489,21 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x01, }, - }, - [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = { + .mute = { + .name = name_mute, + .amux = LINE1, + .gpio = 0x00, + }, + }, + [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = { .name = "Avermedia AVerTV GO 007 FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x00300003, -// .gpiomask = 0x8c240003, + /* .gpiomask = 0x8c240003, */ .inputs = {{ .name = name_tv, .vmux = 1, @@ -1350,16 +1526,24 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x00300001, }, - }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, [SAA7134_BOARD_AVERMEDIA_CARDBUS] = { - /* Jon Westgate */ - .name = "AVerMedia Cardbus TV/Radio", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + /* Kees.Blom@cwi.nl */ + .name = "AVerMedia Cardbus TV/Radio (E500)", + .audio_clock = 0x187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = TV, .tv = 1, },{ .name = name_comp1, @@ -1368,10 +1552,10 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, + .amux = LINE1, }}, .radio = { - .name = name_radio, + .name = name_radio, .amux = LINE1, }, }, @@ -1379,119 +1563,134 @@ struct saa7134_board saa7134_boards[] = { .name = "Terratec Cinergy 400 mobile", .audio_clock = 0x187de7, .tuner_type = TUNER_ALPS_TSBE5_PAL, - .tda9887_conf = TDA9887_PRESENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ - .name = name_tv, + .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, }}, }, [SAA7134_BOARD_CINERGY600_MK3] = { - .name = "Terratec Cinergy 600 TV MK3", - .audio_clock = 0x00200000, + .name = "Terratec Cinergy 600 TV MK3", + .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }}, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { + /* Dylan Walkden */ + .name = "Compro VideoMate Gold+ Pal", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x1ce780, + .inputs = {{ + .name = name_svideo, + .vmux = 0, /* CVideo over SVideo Connector - ok? */ + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x008080, + }}, .radio = { .name = name_radio, .amux = LINE2, - }, - }, - [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { - /* Dylan Walkden */ - .name = "Compro VideoMate Gold+ Pal", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .gpiomask = 0x1ce780, - .inputs = {{ - .name = name_svideo, - .vmux = 0, // CVideo over SVideo Connector - ok? - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x008080, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x80000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x0c8000, - }, - }, + .gpio = 0x80000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x0c8000, + }, + }, [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = { - .name = "Pinnacle PCTV 300i DVB-T + PAL", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, + .name = "Pinnacle PCTV 300i DVB-T + PAL", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, [SAA7134_BOARD_PROVIDEO_PV952] = { /* andreas.kretschmer@web.de */ .name = "ProVideo PV952", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_comp1, @@ -1503,151 +1702,307 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .tv = 1, },{ - .name = name_tv_mono, - .vmux = 1, + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_AVERMEDIA_305] = { + /* much like the "studio" version but without radio + * and another tuner (sirspiritus@yandex.ru) */ + .name = "AverMedia AverTV/305", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_FLYDVBTDUO] = { + /* LifeView FlyDVB-T DUO */ + /* "Nico Sabbi Hartmut Hackmann hartmut.hackmann@t-online.de*/ + .name = "LifeView FlyDVB-T DUO", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, .amux = LINE2, - .tv = 1, }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, }, - [SAA7134_BOARD_AVERMEDIA_305] = { - /* much like the "studio" version but without radio - * and another tuner (sirspiritus@yandex.ru) */ - .name = "AverMedia AverTV/305", + [SAA7134_BOARD_PHILIPS_TOUGH] = { + .name = "Philips TOUGH DVB-T reference design", + .tuner_type = TUNER_ABSENT, + .audio_clock = 0x00187de7, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_AVERMEDIA_307] = { + /* + Davydov Vladimir + */ + .name = "Avermedia AVerTV 307", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = TV, .tv = 1, },{ .name = name_comp1, .vmux = 0, - .amux = LINE2, + .amux = LINE1, },{ .name = name_comp2, .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_ADS_INSTANT_TV] = { + .name = "ADS Tech Instant TV (saa7135)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, .amux = LINE2, },{ .name = name_svideo, .vmux = 8, .amux = LINE2, }}, - .mute = { - .name = name_mute, - .amux = LINE1, + }, + [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = { + .name = "Kworld/Tevion V-Stream Xpert TV PVR7134", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_PAL_I, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x0700, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x000, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x200, /* gpio by DScaler */ + },{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x200, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x100, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x000, }, }, - [SAA7134_BOARD_FLYDVBTDUO] = { - /* LifeView FlyDVB-T DUO */ - /* "Nico Sabbi */ - .name = "LifeView FlyDVB-T DUO", + [SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS] = { + .name = "Typhoon DVB-T Duo Digital/Analog Cardbus", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, -// .gpiomask = 0xe000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + /* .gpiomask = 0xe000, */ .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, -// .gpio = 0x0000, + /* .gpio = 0x0000, */ .tv = 1, - },{ + },{ .name = name_comp1, /* Composite signal on S-Video input */ .vmux = 0, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ },{ .name = name_comp2, /* Composite input */ .vmux = 3, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ },{ .name = name_svideo, /* S-Video signal on S-Video input */ .vmux = 8, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, }, - [SAA7134_BOARD_AVERMEDIA_307] = { - /* - Davydov Vladimir - */ - .name = "Avermedia AVerTV 307", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_ADS_INSTANT_TV] = { - .name = "ADS Tech Instant TV (saa7135)", + [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = { + .name = "Compro VideoMate TV Gold+II", + .audio_clock = 0x002187de7, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x63, + .radio_addr = 0x60, + .gpiomask = 0x8c1880, + .inputs = {{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x800800, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x801000, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x800000, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x880000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x840000, + }, + }, + [SAA7134_BOARD_KWORLD_XPERT] = { + /* + FIXME: + - Remote control doesn't initialize properly. + - Audio volume starts muted, + then gradually increases after channel change. + - Overlay scaling problems (application error?) + - Composite S-Video untested. + From: Konrad Rzepecki + */ + .name = "Kworld Xpert TV PVR7134", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = { - .name = "Kworld/Tevion V-Stream Xpert TV PVR7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL_I, - .gpiomask = 0x0700, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, //gpio by DScaler - },{ - .name = name_svideo, - .vmux = 0, - .amux = LINE1, - .gpio = 0x200, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x100, - }, - }, - }; + .tuner_type = TUNER_TENA_9533_DI, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x61, + .radio_addr = 0x60, + .gpiomask = 0x0700, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x000, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x200, /* gpio by DScaler */ + },{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x200, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x100, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x000, + }, + }, +}; + const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -1661,13 +2016,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2001, .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2001, .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_PHILIPS, @@ -1676,70 +2031,70 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x4e85, + .subvendor = 0x1131, + .subdevice = 0x4e85, .driver_data = SAA7134_BOARD_MONSTERTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1142, - .driver_data = SAA7134_BOARD_CINERGY400, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1143, - .driver_data = SAA7134_BOARD_CINERGY600, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1158, - .driver_data = SAA7134_BOARD_CINERGY600_MK3, - },{ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1142, + .driver_data = SAA7134_BOARD_CINERGY400, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1143, + .driver_data = SAA7134_BOARD_CINERGY600, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1158, + .driver_data = SAA7134_BOARD_CINERGY600_MK3, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, .subdevice = 0x1162, .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5168, .subdevice = 0x0138, .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, //"Typhoon PCI Capture TV Card" Art.No. 50673 - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ + .subdevice = 0x0138, + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x5168, .subdevice = 0x0138, .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, .subdevice = 0x0212, /* minipci, LR212 */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, /* Animation Technologies (LifeView) */ .subdevice = 0x0214, /* Standard PCI, LR214WF */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1489, /* KYE */ .subdevice = 0x0214, /* Genius VideoWonder ProTV */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x16be, @@ -1758,36 +2113,36 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x226b, .driver_data = SAA7134_BOARD_ELSA_500TV, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4842, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4842, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4845, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4830, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4845, - .driver_data = SAA7135_BOARD_ASUSTeK_TVFM7135, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4843, + .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4830, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4843, - .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4840, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4840, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_PHILIPS, @@ -1808,118 +2163,118 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x7133, + .subvendor = 0x1131, + .subdevice = 0x7133, .driver_data = SAA7134_BOARD_VA1000POWER, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2001, .driver_data = SAA7134_BOARD_10MOONSTVMASTER, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_MATROX, - .subdevice = 0x48d0, + .subvendor = PCI_VENDOR_ID_MATROX, + .subdevice = 0x48d0, .driver_data = SAA7134_BOARD_CRONOS_PLUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70b, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa70b, .driver_data = SAA7134_BOARD_MD2819, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2115, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2115, .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2108, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2108, .driver_data = SAA7134_BOARD_AVERMEDIA_305, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x10ff, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x10ff, .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, - },{ + },{ /* AVerMedia CardBus */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xd6ee, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xd6ee, .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, },{ /* TransGear 3000TV */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x050c, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x050c, .driver_data = SAA7134_BOARD_TG3000TV, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002b, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002d, - .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb4, - .driver_data = SAA7134_BOARD_ECS_TVP3XP, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1019, - .subdevice = 0x4cb5, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x12ab, - .subdevice = 0x0800, - .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x11bd, + .subdevice = 0x002b, + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x11bd, + .subdevice = 0x002d, + .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1019, + .subdevice = 0x4cb4, + .driver_data = SAA7134_BOARD_ECS_TVP3XP, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1019, + .subdevice = 0x4cb5, + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x12ab, + .subdevice = 0x0800, + .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x153B, .subdevice = 0x1152, .driver_data = SAA7134_BOARD_CINERGY200, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0, + .subvendor = 0x1131, + .subdevice = 0, .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -1939,18 +2294,24 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x185b, .subdevice = 0xc200, .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x1540, .subdevice = 0x9524, .driver_data = SAA7134_BOARD_PROVIDEO_PV952, - },{ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x0502, /* Cardbus version */ + .driver_data = SAA7134_BOARD_FLYDVBTDUO, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, - .subdevice = 0x0306, + .subdevice = 0x0306, /* PCI version */ .driver_data = SAA7134_BOARD_FLYDVBTDUO, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -1959,31 +2320,44 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xf31f, .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2004, + .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1421, .subdevice = 0x0350, /* PCI version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1421, .subdevice = 0x0370, /* cardbus version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ + },{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x0502, + .driver_data = SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS, + + },{ /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0, .driver_data = SAA7134_BOARD_NOAUTO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0, .driver_data = SAA7134_BOARD_NOAUTO, },{ @@ -1991,26 +2365,26 @@ struct pci_device_id saa7134_pci_tbl[] = { /* --- default catch --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, },{ /* --- end of list --- */ @@ -2021,46 +2395,9 @@ MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); /* ----------------------------------------------------------- */ /* flyvideo tweaks */ -#if 0 -static struct { - char *model; - int tuner_type; -} fly_list[0x20] = { - /* default catch ... */ - [ 0 ... 0x1f ] = { - .model = "UNKNOWN", - .tuner_type = TUNER_ABSENT, - }, - /* ... the ones known so far */ - [ 0x05 ] = { - .model = "PAL-BG", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - }, - [ 0x10 ] = { - .model = "PAL-BG / PAL-DK", - .tuner_type = TUNER_PHILIPS_PAL, - }, - [ 0x15 ] = { - .model = "NTSC", - .tuner_type = TUNER_ABSENT /* FIXME */, - }, -}; -#endif static void board_flyvideo(struct saa7134_dev *dev) { -#if 0 - /* non-working attempt to detect the correct tuner type ... */ - u32 value; - int index; - - value = dev->gpio_value; - index = (value & 0x1f00) >> 8; - printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n", - dev->name, value, fly_list[index].model, - fly_list[index].tuner_type); - dev->tuner_type = fly_list[index].tuner_type; -#endif printk("%s: there are different flyvideo cards with different tuners\n" "%s: out there, you might have to use the tuner= insmod\n" "%s: option to override the default value.\n", @@ -2071,7 +2408,7 @@ static void board_flyvideo(struct saa7134_dev *dev) int saa7134_board_init1(struct saa7134_dev *dev) { - // Always print gpio, often manufacturers encode tuner type and other info. + /* Always print gpio, often manufacturers encode tuner type and other info. */ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); @@ -2082,7 +2419,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = 1; board_flyvideo(dev); break; - case SAA7134_BOARD_FLYTVPLATINUM_FM: + case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: case SAA7134_BOARD_CINERGY600_MK3: @@ -2090,23 +2427,25 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ECS_TVP3XP_4CB5: case SAA7134_BOARD_MD2819: case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: + case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: -// case SAA7134_BOARD_SABRENT_SBTTVFM: /* not finished yet */ +/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: - case SAA7134_BOARD_MANLI_MTV001: - case SAA7134_BOARD_MANLI_MTV002: + case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: + case SAA7134_BOARD_MANLI_MTV001: + case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_AVACSSMARTTV: dev->has_remote = 1; break; case SAA7134_BOARD_MD5044: printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -2114,11 +2453,19 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); msleep(1); break; + case SAA7134_BOARD_FLYDVBTDUO: + case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS: + /* turn the fan on Hac: static for the time being */ + saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); + saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); + break; + case SAA7134_BOARD_AVERMEDIA_CARDBUS: + /* power-up tuner chip */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); + msleep(1); + break; } - if (dev->has_remote) - dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | - SAA7134_IRQ2_INTE_GPIO18A | - SAA7134_IRQ2_INTE_GPIO16 ); return 0; } @@ -2139,10 +2486,85 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; dev->board = board; printk("%s: board type fixup: %s\n", dev->name, - saa7134_boards[dev->board].name); + saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (TUNER_ABSENT != dev->tuner_type) - saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&dev->tuner_type); + + if (TUNER_ABSENT != dev->tuner_type) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = ADDR_UNSET; + + saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + break; +case SAA7134_BOARD_MD7134: + { + struct tuner_setup tun_setup; + u8 subaddr; + u8 data[3]; + int ret, tuner_t; + + struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, + {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; + subaddr= 0x14; + tuner_t = 0; + ret = i2c_transfer(&dev->i2c_adap, msg, 2); + if (ret != 2) { + printk(KERN_ERR "EEPROM read failure\n"); + } else if ((data[0] != 0) && (data[0] != 0xff)) { + /* old config structure */ + subaddr = data[0] + 2; + msg[1].len = 2; + i2c_transfer(&dev->i2c_adap, msg, 2); + tuner_t = (data[0] << 8) + data[1]; + switch (tuner_t){ + case 0x0103: + dev->tuner_type = TUNER_PHILIPS_PAL; + break; + case 0x010C: + dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + default: + printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + } + } else if ((data[1] != 0) && (data[1] != 0xff)) { + /* new config structure */ + subaddr = data[1] + 1; + msg[1].len = 1; + i2c_transfer(&dev->i2c_adap, msg, 2); + subaddr = data[0] + 1; + msg[1].len = 2; + i2c_transfer(&dev->i2c_adap, msg, 2); + tuner_t = (data[1] << 8) + data[0]; + switch (tuner_t) { + case 0x0005: + dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + case 0x001d: + dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3; + printk(KERN_INFO "%s Board has DVB-T\n", dev->name); + break; + default: + printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + } + } else { + printk(KERN_ERR "%s unexpected config structure\n", dev->name); + } + + printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); + if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { + dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); + } + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = ADDR_UNSET; + + saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); + } break; } return 0; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index f61ed1849a2..1dbe61755e9 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-core.c,v 1.30 2005/05/22 19:23:39 nsh Exp $ + * $Id: saa7134-core.c,v 1.39 2005/07/05 17:37:35 nsh Exp $ * * device driver for philips saa7134 based TV cards * driver core @@ -183,46 +183,6 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) /* ------------------------------------------------------------------ */ -#if 0 -static char *dec1_bits[8] = { - "DCSTD0", "DCSCT1", "WIPA", "GLIMB", - "GLIMT", "SLTCA", "HLCK" -}; -static char *dec2_bits[8] = { - "RDCAP", "COPRO", "COLSTR", "TYPE3", - NULL, "FIDT", "HLVLN", "INTL" -}; -static char *scale1_bits[8] = { - "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B" -}; -static char *scale2_bits[8] = { - "TRERR", "CFERR", "LDERR", "WASRST", - "FIDSCI", "FIDSCO", "D6^D5", "TASK" -}; - -static void dump_statusreg(struct saa7134_dev *dev, int reg, - char *regname, char **bits) -{ - int value,i; - - value = saa_readb(reg); - printk(KERN_DEBUG "%s: %s:", dev->name, regname); - for (i = 7; i >= 0; i--) { - if (NULL == bits[i]) - continue; - printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0); - } - printk("\n"); -} - -static void dump_statusregs(struct saa7134_dev *dev) -{ - dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits); - dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits); -} -#endif /* ----------------------------------------------------------- */ /* delayed request_module */ @@ -616,10 +576,6 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) if (irq_debug) print_irqstatus(dev,loop,report,status); -#if 0 - if (report & SAA7134_IRQ_REPORT_CONF_ERR) - dump_statusregs(dev); -#endif if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) saa7134_irq_video_intl(dev); @@ -711,7 +667,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_EVFE1 | SAA7134_MAIN_CTRL_EVFE2 | SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBADC | SAA7134_MAIN_CTRL_EBDAC); /* enable peripheral devices */ @@ -726,14 +681,28 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) /* late init (with i2c + irq) */ static int saa7134_hwinit2(struct saa7134_dev *dev) { + unsigned int irq2_mask; dprintk("hwinit2\n"); saa7134_video_init2(dev); saa7134_tvaudio_init2(dev); /* enable IRQ's */ + irq2_mask = + SAA7134_IRQ2_INTE_DEC3 | + SAA7134_IRQ2_INTE_DEC2 | + SAA7134_IRQ2_INTE_DEC1 | + SAA7134_IRQ2_INTE_DEC0 | + SAA7134_IRQ2_INTE_PE | + SAA7134_IRQ2_INTE_AR; + + if (dev->has_remote) + irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | + SAA7134_IRQ2_INTE_GPIO18A | + SAA7134_IRQ2_INTE_GPIO16 ); + saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, dev->irq2_mask); + saa_writel(SAA7134_IRQ2, irq2_mask); return 0; } @@ -954,13 +923,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* initialize hardware #1 */ - dev->irq2_mask = - SAA7134_IRQ2_INTE_DEC3 | - SAA7134_IRQ2_INTE_DEC2 | - SAA7134_IRQ2_INTE_DEC1 | - SAA7134_IRQ2_INTE_DEC0 | - SAA7134_IRQ2_INTE_PE | - SAA7134_IRQ2_INTE_AR; saa7134_board_init1(dev); saa7134_hwinit1(dev); @@ -990,6 +952,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, request_module("saa6752hs"); request_module_depend("saa7134-empress",&need_empress); } + if (card_is_dvb(dev)) request_module_depend("saa7134-dvb",&need_dvb); @@ -1144,9 +1107,6 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); -#if 0 /* causes some trouble when reinserting the driver ... */ - pci_disable_device(pci_dev); -#endif pci_set_drvdata(pci_dev, NULL); /* free memory */ diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index b6f002e8421..93dd6197854 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-i2c.c,v 1.11 2005/06/12 01:36:14 mchehab Exp $ + * $Id: saa7134-i2c.c,v 1.19 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * i2c interface support @@ -197,10 +197,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, enum i2c_status status; __u32 dword; -#if 0 - i2c_set_attr(dev,attr); - saa_writeb(SAA7134_I2C_DATA, data); -#else /* have to write both attr + data in one 32bit word */ dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); dword &= 0x0f; @@ -210,7 +206,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, // dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); -#endif d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); if (!i2c_is_busy_wait(dev)) @@ -331,12 +326,44 @@ static u32 functionality(struct i2c_adapter *adap) static int attach_inform(struct i2c_client *client) { - struct saa7134_dev *dev = client->adapter->algo_data; + struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; int conf = dev->tda9887_conf; + struct tuner_setup tun_setup; + + d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->name,client->addr,i2c_clientname(client)); + + if (!client->driver->command) + return 0; + + if (saa7134_boards[dev->board].radio_type != UNSET) { + + tun_setup.type = saa7134_boards[dev->board].radio_type; + tun_setup.addr = saa7134_boards[dev->board].radio_addr; + + if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) { + tun_setup.mode_mask = T_RADIO; + + client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + + if (tuner != UNSET) { + + tun_setup.type = tuner; + tun_setup.addr = saa7134_boards[dev->board].tuner_addr; + + if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { + + tun_setup.mode_mask = T_ANALOG_TV; + + client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + + client->driver->command(client, TDA9887_SET_CONFIG, &conf); - saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index aba2b9de60d..213740122fe 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-input.c,v 1.19 2005/06/07 18:02:26 nsh Exp $ + * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 nsh Exp $ * * handle saa7134 IR remotes via linux kernel input layer. * @@ -68,10 +68,8 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = { [ 6 ] = KEY_AGAIN, // Recal [ 16 ] = KEY_KPENTER, // Enter -#if 1 /* FIXME */ [ 26 ] = KEY_F22, // Stereo [ 24 ] = KEY_EDIT, // AV Source -#endif }; static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { @@ -172,45 +170,45 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { }; static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = { - [ 30 ] = KEY_POWER, // power + [ 30 ] = KEY_POWER, // power [ 28 ] = KEY_SEARCH, // scan - [ 7 ] = KEY_SELECT, // source + [ 7 ] = KEY_SELECT, // source [ 22 ] = KEY_VOLUMEUP, [ 20 ] = KEY_VOLUMEDOWN, - [ 31 ] = KEY_CHANNELUP, + [ 31 ] = KEY_CHANNELUP, [ 23 ] = KEY_CHANNELDOWN, [ 24 ] = KEY_MUTE, [ 2 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 11 ] = KEY_KP2, - [ 27 ] = KEY_KP3, - [ 5 ] = KEY_KP4, - [ 9 ] = KEY_KP5, - [ 21 ] = KEY_KP6, + [ 1 ] = KEY_KP1, + [ 11 ] = KEY_KP2, + [ 27 ] = KEY_KP3, + [ 5 ] = KEY_KP4, + [ 9 ] = KEY_KP5, + [ 21 ] = KEY_KP6, [ 6 ] = KEY_KP7, - [ 10 ] = KEY_KP8, + [ 10 ] = KEY_KP8, [ 18 ] = KEY_KP9, [ 16 ] = KEY_KPDOT, [ 3 ] = KEY_TUNER, // tv/fm - [ 4 ] = KEY_REWIND, // fm tuning left or function left - [ 12 ] = KEY_FORWARD, // fm tuning right or function right + [ 4 ] = KEY_REWIND, // fm tuning left or function left + [ 12 ] = KEY_FORWARD, // fm tuning right or function right [ 0 ] = KEY_RECORD, - [ 8 ] = KEY_STOP, - [ 17 ] = KEY_PLAY, + [ 8 ] = KEY_STOP, + [ 17 ] = KEY_PLAY, [ 25 ] = KEY_ZOOM, [ 14 ] = KEY_MENU, // function [ 19 ] = KEY_AGAIN, // recall [ 29 ] = KEY_RESTART, // reset + [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle // FIXME [ 13 ] = KEY_F21, // mts - [ 15 ] = KEY_F22, // min - [ 26 ] = KEY_F23, // freeze + [ 15 ] = KEY_F22, // min }; /* Alex Hermann */ @@ -489,13 +487,14 @@ int saa7134_input_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_ECS_TVP3XP: case SAA7134_BOARD_ECS_TVP3XP_4CB5: - ir_codes = eztv_codes; - mask_keycode = 0x00017c; - mask_keyup = 0x000002; + ir_codes = eztv_codes; + mask_keycode = 0x00017c; + mask_keyup = 0x000002; polling = 50; // ms - break; + break; + case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVACSSMARTTV: - ir_codes = avacssmart_codes; + ir_codes = avacssmart_codes; mask_keycode = 0x00001F; mask_keyup = 0x000020; polling = 50; // ms @@ -524,6 +523,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; // ms break; case SAA7134_BOARD_VIDEOMATE_TV_PVR: + case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: ir_codes = videomate_tv_pvr_codes; mask_keycode = 0x00003F; mask_keyup = 0x400000; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 81732904623..b5bede95dbf 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-oss.c,v 1.14 2005/05/18 22:45:16 hhackmann Exp $ + * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * oss dsp interface @@ -556,21 +556,28 @@ mixer_recsrc_7134(struct saa7134_dev *dev) static int mixer_recsrc_7133(struct saa7134_dev *dev) { - u32 value = 0xbbbbbb; + u32 anabar, xbarin; + xbarin = 0x03; // adc + anabar = 0; switch (dev->oss.input) { case TV: - value = 0xbbbb10; /* MAIN */ + xbarin = 0; // Demodulator + anabar = 2; // DACs break; case LINE1: - value = 0xbbbb32; /* AUX1 */ + anabar = 0; // aux1, aux1 break; case LINE2: case LINE2_LEFT: - value = 0xbbbb54; /* AUX2 */ + anabar = 9; // aux2, aux2 break; } - saa_dsp_writel(dev, 0x46c >> 2, value); + /* output xbar always main channel */ + saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10); + saa_dsp_writel(dev, 0x464 >> 2, xbarin); + saa_writel(0x594 >> 2, anabar); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 345eb2a8c28..4dd9f1b2392 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $ + * $Id: saa7134-ts.c,v 1.15 2005/06/14 22:48:18 hhackmann Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -221,10 +221,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if (dev->ts_q.curr) { field = dev->ts_q.curr->vb.field; if (field == V4L2_FIELD_TOP) { - if ((status & 0x100000) != 0x000000) + if ((status & 0x100000) != 0x100000) goto done; } else { - if ((status & 0x100000) != 0x100000) + if ((status & 0x100000) != 0x000000) goto done; } saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 3617e7f7a41..eeafa5a71d2 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-tvaudio.c,v 1.25 2005/06/07 19:00:38 nsh Exp $ + * $Id: saa7134-tvaudio.c,v 1.30 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * tv audio decoder (fm stereo, nicam, ...) @@ -169,7 +169,7 @@ static void tvaudio_init(struct saa7134_dev *dev) int clock = saa7134_boards[dev->board].audio_clock; if (UNSET != audio_clock_override) - clock = audio_clock_override; + clock = audio_clock_override; /* init all audio registers */ saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); @@ -219,14 +219,17 @@ static void mute_input_7134(struct saa7134_dev *dev) in = dev->input; mute = (dev->ctl_mute || (dev->automute && (&card(dev).radio) != in)); - if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device && - card(dev).mute.name) { - /* 7130 - we'll mute using some unconnected audio input */ + if (card(dev).mute.name) { + /* + * 7130 - we'll mute using some unconnected audio input + * 7134 - we'll probably should switch external mux with gpio + */ if (mute) in = &card(dev).mute; } + if (dev->hw_mute == mute && - dev->hw_input == in) { + dev->hw_input == in) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; @@ -260,6 +263,7 @@ static void mute_input_7134(struct saa7134_dev *dev) /* switch gpio-connected external audio mux */ if (0 == card(dev).gpiomask) return; + mask = card(dev).gpiomask; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); @@ -339,13 +343,8 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { -#if 0 - /* hmm, that one doesn't return on wakeup ... */ - msleep_interruptible(timeout); -#else set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(timeout)); -#endif } } remove_wait_queue(&dev->thread.wq, &wait); @@ -400,27 +399,10 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) return value; } -#if 0 -static void sifdebug_dump_regs(struct saa7134_dev *dev) -{ - print_regb(AUDIO_STATUS); - print_regb(IDENT_SIF); - print_regb(LEVEL_READOUT1); - print_regb(LEVEL_READOUT2); - print_regb(DCXO_IDENT_CTRL); - print_regb(DEMODULATOR); - print_regb(AGC_GAIN_SELECT); - print_regb(MONITOR_SELECT); - print_regb(FM_DEEMPHASIS); - print_regb(FM_DEMATRIX); - print_regb(SIF_SAMPLE_FREQ); - print_regb(ANALOG_IO_SELECT); -} -#endif static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio) { - __u32 idp,nicam; + __u32 idp, nicam, nicam_status; int retval = -1; switch (audio->mode) { @@ -442,18 +424,24 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; case TVAUDIO_NICAM_FM: case TVAUDIO_NICAM_AM: - nicam = saa_readb(SAA7134_NICAM_STATUS); + nicam = saa_readb(SAA7134_AUDIO_STATUS); dprintk("getstereo: nicam=0x%x\n",nicam); - switch (nicam & 0x0b) { - case 0x08: - retval = V4L2_TUNER_SUB_MONO; - break; - case 0x09: - retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x0a: - retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - break; + if (nicam & 0x1) { + nicam_status = saa_readb(SAA7134_NICAM_STATUS); + dprintk("getstereo: nicam_status=0x%x\n", nicam_status); + + switch (nicam_status & 0x03) { + case 0x01: + retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x02: + retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + break; + default: + retval = V4L2_TUNER_SUB_MONO; + } + } else { + /* No nicam detected */ } break; } @@ -489,15 +477,15 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: + case TVAUDIO_NICAM_AM: + case TVAUDIO_NICAM_FM: dprintk("setstereo [fm] => %s\n", name[ mode % ARRAY_SIZE(name) ]); reg = fm[ mode % ARRAY_SIZE(fm) ]; saa_writeb(SAA7134_FM_DEMATRIX, reg); break; case TVAUDIO_FM_SAT_STEREO: - case TVAUDIO_NICAM_AM: - case TVAUDIO_NICAM_FM: - /* FIXME */ + /* Not implemented */ break; } return 0; @@ -596,7 +584,7 @@ static int tvaudio_thread(void *data) /* find the exact tv audio norm */ for (audio = UNSET, i = 0; i < TVAUDIO; i++) { if (dev->tvnorm->id != UNSET && - !(dev->tvnorm->id & tvaudio[i].std)) + !(dev->tvnorm->id & tvaudio[i].std)) continue; if (tvaudio[i].carr1 != carrier) continue; @@ -703,24 +691,6 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) return 0; } -#if 0 -static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value) -{ - int err; - - d2printk("dsp read reg 0x%x\n", reg<<2); - saa_readl(reg); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB); - if (err < 0) - return err; - *value = saa_readl(reg); - d2printk("dsp read => 0x%06x\n", *value & 0xffffff); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA); - if (err < 0) - return err; - return 0; -} -#endif int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) { @@ -753,31 +723,50 @@ static int getstereo_7133(struct saa7134_dev *dev) static int mute_input_7133(struct saa7134_dev *dev) { u32 reg = 0; + u32 xbarin, xbarout; int mask; + struct saa7134_input *in; + /* Hac 0506 route OSS sound simultanously */ + xbarin = 0x03; switch (dev->input->amux) { case TV: reg = 0x02; + xbarin = 0; break; case LINE1: reg = 0x00; break; case LINE2: case LINE2_LEFT: - reg = 0x01; + reg = 0x09; break; } - if (dev->ctl_mute) + saa_dsp_writel(dev, 0x464 >> 2, xbarin); + if (dev->ctl_mute) { reg = 0x07; + xbarout = 0xbbbbbb; + } else + xbarout = 0xbbbb10; + saa_dsp_writel(dev, 0x46c >> 2, xbarout); + saa_writel(0x594 >> 2, reg); + /* switch gpio-connected external audio mux */ if (0 != card(dev).gpiomask) { mask = card(dev).gpiomask; + + if (card(dev).mute.name && dev->ctl_mute) + in = &card(dev).mute; + else + in = dev->input; + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, dev->input->gpio); - saa7134_track_gpio(dev,dev->input->name); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); + saa7134_track_gpio(dev,in->name); } + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 3c33c591cc8..29e51cad2aa 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -130,13 +130,7 @@ static int buffer_prepare(struct videobuf_queue *q, lines = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; if (lines > VBI_LINE_COUNT) lines = VBI_LINE_COUNT; -#if 1 llength = VBI_LINE_LENGTH; -#else - llength = (norm->h_stop - norm->h_start +1) * 2; - if (llength > VBI_LINE_LENGTH) - llength = VBI_LINE_LENGTH; -#endif size = lines * llength * 2; if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; @@ -178,13 +172,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) int llength,lines; lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1; -#if 1 llength = VBI_LINE_LENGTH; -#else - llength = (norm->h_stop - norm->h_start +1) * 2; - if (llength > VBI_LINE_LENGTH) - llength = VBI_LINE_LENGTH; -#endif *size = lines * llength * 2; if (0 == *count) *count = vbibufs; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index c0a2ee52053..a4c2f751d09 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-video.c,v 1.30 2005/06/07 19:00:38 nsh Exp $ + * $Id: saa7134-video.c,v 1.36 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -274,7 +274,7 @@ static struct saa7134_tvnorm tvnorms[] = { .h_start = 0, .h_stop = 719, - .video_v_start = 23, + .video_v_start = 23, .video_v_stop = 262, .vbi_v_start_0 = 10, .vbi_v_stop_0 = 21, @@ -1204,7 +1204,6 @@ static int video_open(struct inode *inode, struct file *file) struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); if (h->video_dev && (h->video_dev->minor == minor)) @@ -1256,12 +1255,12 @@ static int video_open(struct inode *inode, struct file *file) if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL); + saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } - return 0; + return 0; } static ssize_t @@ -1304,10 +1303,10 @@ video_poll(struct file *file, struct poll_table_struct *wait) } else { down(&fh->cap.lock); if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ + /* need to capture a new frame */ if (res_locked(fh->dev,RESOURCE_VIDEO)) { - up(&fh->cap.lock); - return POLLERR; + up(&fh->cap.lock); + return POLLERR; } if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { up(&fh->cap.lock); @@ -1363,6 +1362,36 @@ static int video_release(struct inode *inode, struct file *file) res_free(dev,fh,RESOURCE_VBI); } + /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ + saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); + + if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { + u8 data[2]; + int ret; + struct i2c_msg msg = {.addr=I2C_ADDR_TDA8290, .flags=0, .buf=data, .len = 2}; + data[0] = 0x21; + data[1] = 0xc0; + ret = i2c_transfer(&dev->i2c_adap, &msg, 1); + if (ret != 1) + printk(KERN_ERR "TDA8290 access failure\n"); + msg.addr = I2C_ADDR_TDA8275; + data[0] = 0x30; + data[1] = 0xd0; + ret = i2c_transfer(&dev->i2c_adap, &msg, 1); + if (ret != 1) + printk(KERN_ERR "TDA8275 access failure\n"); + msg.addr = I2C_ADDR_TDA8290; + data[0] = 0x21; + data[1] = 0x80; + i2c_transfer(&dev->i2c_adap, &msg, 1); + data[0] = 0x00; + data[1] = 0x02; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + /* free stuff */ videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); @@ -1399,13 +1428,6 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ -#if 0 - if (V4L2_STD_PAL == norm->id) { - /* FIXME */ - f->fmt.vbi.start[0] += 3; - f->fmt.vbi.start[1] += 3*2; - } -#endif } static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, @@ -2120,8 +2142,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - t->rangelow = (int)(65*16); - t->rangehigh = (int)(108*16); saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index d6b1c0d4d0f..6836c07794f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -1,5 +1,5 @@ /* - * $Id: saa7134.h,v 1.41 2005/06/07 18:02:26 nsh Exp $ + * $Id: saa7134.h,v 1.48 2005/07/01 08:22:24 nsh Exp $ * * v4l2 device driver for philips saa7134 based TV cards * @@ -46,8 +46,6 @@ #endif #define UNSET (-1U) -/* 2.4 / 2.5 driver compatibility stuff */ - /* ----------------------------------------------------------- */ /* enums */ @@ -159,7 +157,7 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33 #define SAA7134_BOARD_NOVAC_PRIMETV7133 34 #define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35 -#define SAA7133_BOARD_UPMOST_PURPLE_TV 36 +#define SAA7134_BOARD_UPMOST_PURPLE_TV 36 #define SAA7134_BOARD_ITEMS_MTV005 37 #define SAA7134_BOARD_CINERGY200 38 #define SAA7134_BOARD_FLYTVPLATINUM_MINI 39 @@ -176,13 +174,17 @@ struct saa7134_format { #define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50 #define SAA7134_BOARD_PROVIDEO_PV952 51 #define SAA7134_BOARD_AVERMEDIA_305 52 -#define SAA7135_BOARD_ASUSTeK_TVFM7135 53 +#define SAA7134_BOARD_ASUSTeK_TVFM7135 53 #define SAA7134_BOARD_FLYTVPLATINUM_FM 54 #define SAA7134_BOARD_FLYDVBTDUO 55 #define SAA7134_BOARD_AVERMEDIA_307 56 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57 #define SAA7134_BOARD_ADS_INSTANT_TV 58 #define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59 +#define SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS 60 +#define SAA7134_BOARD_PHILIPS_TOUGH 61 +#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 +#define SAA7134_BOARD_KWORLD_XPERT 63 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -213,6 +215,10 @@ struct saa7134_board { /* i2c chip info */ unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + unsigned int tda9887_conf; /* peripheral I/O */ @@ -403,9 +409,12 @@ struct saa7134_dev { /* config info */ unsigned int board; unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + unsigned int tda9887_conf; unsigned int gpio_value; - unsigned int irq2_mask; /* i2c i/o */ struct i2c_adapter i2c_adap; -- cgit v1.2.3 From af9eeed2d78cb9c672bdc750133506670713fdf8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:06 -0700 Subject: [PATCH] v4l: tuner-3026 - replace obsolete ioctl value - obsolete TUNER_SET_TVFREQ changed to VIDIOCSFREQ. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/tuner-3036.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 51748c6578d..7d825e510ff 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -152,7 +152,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { - case TUNER_SET_TVFREQ: + case VIDIOCSFREQ: set_tv_freq(client, *iarg); break; -- cgit v1.2.3 From 833e9a1abe8cdfc037964d3240d57bb8ff94bff0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:07 -0700 Subject: [PATCH] v4l: TV EEPROM - Eliminated unused code. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/tveeprom.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 0f03c25489f..e8d9440977c 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -400,14 +400,6 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data } } -#if 0 - if (t_format < sizeof(hauppauge_tuner_fmt)/sizeof(struct HAUPPAUGE_TUNER_FMT)) { - tvee->tuner_formats = hauppauge_tuner_fmt[t_format].id; - t_fmt_name = hauppauge_tuner_fmt[t_format].name; - } else { - t_fmt_name = ""; - } -#endif TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n", tvee->model, @@ -482,6 +474,7 @@ static unsigned short normal_i2c[] = { 0xa0 >> 1, I2C_CLIENT_END, }; + I2C_CLIENT_INSMOD; struct i2c_driver i2c_driver_tveeprom; -- cgit v1.2.3 From 55ee3b8365fd5d301b9076eea739146f2b91e82c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 12 Jul 2005 13:59:08 -0700 Subject: [PATCH] v4l: broken hybrid dvb inclusion Always include dvb frontend code for hybrid cx88 and saa7134 boards. Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-dvb.c | 5 +++++ drivers/media/video/saa7134/saa7134-dvb.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 5544e1d6a34..8db68f2d135 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -30,6 +30,11 @@ #include #include +#define CONFIG_DVB_MT352 1 +#define CONFIG_DVB_CX22702 1 +#define CONFIG_DVB_OR51132 1 +#define CONFIG_DVB_LGDT3302 1 + #include "cx88.h" #include "dvb-pll.h" diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 3959a571486..334bc185009 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -30,6 +30,9 @@ #include #include +#define CONFIG_DVB_MT352 1 +#define CONFIG_DVB_TDA1004X 1 + #include "saa7134-reg.h" #include "saa7134.h" -- cgit v1.2.3 From f6a80ea8ed44de0b19c42d41928be37a186a3f41 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:01 -0700 Subject: [PATCH] device-mapper multipath: Barriers not supported dm multipath will report barriers as not supported with this patch. Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 6 ++++++ drivers/md/dm-snap.c | 2 +- drivers/md/dm.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 0c1b8520ef8..84cdb700a24 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -765,6 +765,9 @@ static int multipath_map(struct dm_target *ti, struct bio *bio, struct mpath_io *mpio; struct multipath *m = (struct multipath *) ti->private; + if (bio_barrier(bio)) + return -EOPNOTSUPP; + mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); dm_bio_record(&mpio->details, bio); @@ -988,6 +991,9 @@ static int do_end_io(struct multipath *m, struct bio *bio, if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) return error; + if (error == -EOPNOTSUPP) + return error; + spin_lock(&m->lock); if (!m->nr_valid_paths) { if (!m->queue_if_no_path || m->suspended) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7e691ab9a74..594d1f6b478 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -777,7 +777,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, /* Full snapshots are not usable */ if (!s->valid) - return -1; + return -EIO; /* * Write to snapshot - higher level takes care of RW/RO diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f6b03957efc..5d40555b42b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -384,7 +384,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, /* error the io and bail out */ struct dm_io *io = tio->io; free_tio(tio->io->md, tio); - dec_pending(io, -EIO); + dec_pending(io, r); bio_put(clone); } } -- cgit v1.2.3 From a044d016896d2717694003f00d31a98194077511 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:02 -0700 Subject: [PATCH] device-mapper multipath: Flush workqueue when destroying The multipath destructor must flush its workqueue. Otherwise items that reference the destroyed object could remain. From: "goggin, edward" Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 84cdb700a24..fa72f015320 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -752,6 +752,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, static void multipath_dtr(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; + + flush_workqueue(kmultipathd); free_multipath(m); } -- cgit v1.2.3 From 436d41087d047b61f8ab0604dc74fff3240a8933 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:03 -0700 Subject: [PATCH] device-mapper multipath: Avoid possible suspension deadlock To avoid deadlock when suspending a multipath device after all its paths have failed, stop queueing any I/O that is about to fail *before* calling freeze_bdev instead of after. Instead of setting a multipath 'suspended' flag which would have to be reset if an error occurs during the process, save the previous queueing state and leave userspace to restore if it wishes. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 25 +++++++++++++------------ drivers/md/dm.c | 12 +++++++----- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index fa72f015320..98da8eee2d2 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -72,7 +72,7 @@ struct multipath { unsigned queue_io; /* Must we queue all I/O? */ unsigned queue_if_no_path; /* Queue I/O if last path fails? */ - unsigned suspended; /* Has dm core suspended our I/O? */ + unsigned saved_queue_if_no_path;/* Saved state during suspension */ struct work_struct process_queued_ios; struct bio_list queued_ios; @@ -304,7 +304,7 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, m->queue_size--; if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) { + (!pgpath && m->queue_if_no_path)) { /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; @@ -333,6 +333,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) spin_lock_irqsave(&m->lock, flags); + m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; if (!m->queue_if_no_path) queue_work(kmultipathd, &m->process_queued_ios); @@ -391,7 +392,7 @@ static void process_queued_ios(void *data) pgpath = m->current_pgpath; if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) + (!pgpath && m->queue_if_no_path)) must_queue = 1; init_required = m->pg_init_required; @@ -998,7 +999,7 @@ static int do_end_io(struct multipath *m, struct bio *bio, spin_lock(&m->lock); if (!m->nr_valid_paths) { - if (!m->queue_if_no_path || m->suspended) { + if (!m->queue_if_no_path) { spin_unlock(&m->lock); return -EIO; } else { @@ -1059,27 +1060,27 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio, /* * Suspend can't complete until all the I/O is processed so if - * the last path failed we will now error any queued I/O. + * the last path fails we must error any remaining I/O. + * Note that if the freeze_bdev fails while suspending, the + * queue_if_no_path state is lost - userspace should reset it. */ static void multipath_presuspend(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; - unsigned long flags; - spin_lock_irqsave(&m->lock, flags); - m->suspended = 1; - if (m->queue_if_no_path) - queue_work(kmultipathd, &m->process_queued_ios); - spin_unlock_irqrestore(&m->lock, flags); + queue_if_no_path(m, 0); } +/* + * Restore the queue_if_no_path setting. + */ static void multipath_resume(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; unsigned long flags; spin_lock_irqsave(&m->lock, flags); - m->suspended = 0; + m->queue_if_no_path = m->saved_queue_if_no_path; spin_unlock_irqrestore(&m->lock, flags); } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 5d40555b42b..bb3ad79c14d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1055,14 +1055,17 @@ int dm_suspend(struct mapped_device *md) if (test_bit(DMF_BLOCK_IO, &md->flags)) goto out_read_unlock; - error = __lock_fs(md); - if (error) - goto out_read_unlock; - map = dm_get_table(md); if (map) + /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); + error = __lock_fs(md); + if (error) { + dm_table_put(map); + goto out_read_unlock; + } + up_read(&md->lock); /* @@ -1121,7 +1124,6 @@ int dm_suspend(struct mapped_device *md) return 0; out_unfreeze: - /* FIXME Undo dm_table_presuspend_targets */ __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); out_write_unlock: -- cgit v1.2.3 From c3cd4f6b275da0f594797b73f721a4185335478f Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:04 -0700 Subject: [PATCH] device-mapper multipath: Fix pg initialisation races Prevent more than one priority group initialisation function from being outstanding at once. Otherwise the completion functions interfere with each other. Also, reloading the table could reference a freed pointer. Only reset queue_io in pg_init_complete if another pg_init isn't required. Skip process_queued_ios if the queue is empty so that we only trigger a pg_init if there's I/O. Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 98da8eee2d2..785806bdb24 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -63,6 +63,7 @@ struct multipath { unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ + unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ unsigned nr_valid_paths; /* Total number of usable paths */ struct pgpath *current_pgpath; @@ -308,7 +309,8 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; - if (m->pg_init_required || !m->queue_io) + if ((m->pg_init_required && !m->pg_init_in_progress) || + !m->queue_io) queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = 0; @@ -335,7 +337,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; - if (!m->queue_if_no_path) + if (!m->queue_if_no_path && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); @@ -380,25 +382,31 @@ static void process_queued_ios(void *data) { struct multipath *m = (struct multipath *) data; struct hw_handler *hwh = &m->hw_handler; - struct pgpath *pgpath; - unsigned init_required, must_queue = 0; + struct pgpath *pgpath = NULL; + unsigned init_required = 0, must_queue = 1; unsigned long flags; spin_lock_irqsave(&m->lock, flags); + if (!m->queue_size) + goto out; + if (!m->current_pgpath) __choose_pgpath(m); pgpath = m->current_pgpath; - if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path)) - must_queue = 1; + if ((pgpath && !m->queue_io) || + (!pgpath && !m->queue_if_no_path)) + must_queue = 0; - init_required = m->pg_init_required; - if (init_required) + if (m->pg_init_required && !m->pg_init_in_progress) { m->pg_init_required = 0; + m->pg_init_in_progress = 1; + init_required = 1; + } +out: spin_unlock_irqrestore(&m->lock, flags); if (init_required) @@ -843,7 +851,7 @@ static int reinstate_path(struct pgpath *pgpath) pgpath->path.is_active = 1; m->current_pgpath = NULL; - if (!m->nr_valid_paths++) + if (!m->nr_valid_paths++ && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); queue_work(kmultipathd, &m->trigger_event); @@ -969,12 +977,13 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags) bypass_pg(m, pg, 1); spin_lock_irqsave(&m->lock, flags); - if (!err_flags) - m->queue_io = 0; - else { + if (err_flags) { m->current_pgpath = NULL; m->current_pg = NULL; - } + } else if (!m->pg_init_required) + m->queue_io = 0; + + m->pg_init_in_progress = 0; queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); } -- cgit v1.2.3 From 93c534aefb906824d71ea779ed0c7f1573843f4e Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:05 -0700 Subject: [PATCH] device-mapper: Fix dm_swap_table error cases Fix dm_swap_table() __bind error cases: a missing unlock, and EINVAL preferable to EPERM. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index bb3ad79c14d..54fabbf0667 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -966,23 +966,20 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c) */ int dm_swap_table(struct mapped_device *md, struct dm_table *table) { - int r; + int r = -EINVAL; down_write(&md->lock); /* device must be suspended */ - if (!test_bit(DMF_SUSPENDED, &md->flags)) { - up_write(&md->lock); - return -EPERM; - } + if (!test_bit(DMF_SUSPENDED, &md->flags)) + goto out; __unbind(md); r = __bind(md, table); - if (r) - return r; +out: up_write(&md->lock); - return 0; + return r; } /* -- cgit v1.2.3 From d5e404c10a98fc2979643476851e9cbdb1944812 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:05 -0700 Subject: [PATCH] device-mapper snapshots: Handle origin extension Handle writes to a snapshot-origin device that has been extended since the snapshot was taken. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-snap.c | 4 ++++ drivers/md/dm-table.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 594d1f6b478..ab54f99b7c3 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -931,6 +931,10 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) if (!snap->valid) continue; + /* Nothing to do if writing beyond end of snapshot */ + if (bio->bi_sector >= dm_table_get_size(snap->table)) + continue; + down_write(&snap->lock); /* diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 18e9b9953fc..a5a4c0ed8a1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -943,6 +943,7 @@ EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); EXPORT_SYMBOL(dm_table_event); +EXPORT_SYMBOL(dm_table_get_size); EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); -- cgit v1.2.3