diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
commit | 06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch) | |
tree | 8766f208847d4876a6db619aebbf54d53b76eb44 /drivers/sbus/char | |
parent | fa9bdb574f4febb751848a685d9a9017e04e1d53 (diff) |
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r-- | drivers/sbus/char/Makefile | 129 | ||||
-rw-r--r-- | drivers/sbus/char/bpp.c | 2 | ||||
-rw-r--r-- | drivers/sbus/char/envctrl.c | 2112 | ||||
-rw-r--r-- | drivers/sbus/char/sab82532.c | 22 | ||||
-rw-r--r-- | drivers/sbus/char/su.c | 22 | ||||
-rw-r--r-- | drivers/sbus/char/sunkbd.c | 20 | ||||
-rw-r--r-- | drivers/sbus/char/vfc_dev.c | 2 | ||||
-rw-r--r-- | drivers/sbus/char/zs.c | 22 |
8 files changed, 792 insertions, 1539 deletions
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index 7c5a21b2c..ad8b7e140 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -1,128 +1,47 @@ # -# Makefile for the linux kernel. +# Makefile for the kernel miscellaneous SPARC device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... - # Dave Redman Frame Buffer tuning support. -# OK this is kind of ugly but it does allow drivers to be added fairly -# easily. and you can even choose what sort of support you want. +# +# 7 October 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> +# Rewritten to use lists instead of if-statements. +# O_TARGET := sunchar.o O_OBJS := ${O_OBJ} sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o -M_OBJS := -ifeq ($(ARCH),sparc64) +vfc-objs := vfc_dev.o vfc_i2c.o ifeq ($(CONFIG_PCI),y) - -OX_OBJS += su.o -O_OBJS += pcikbd.o - -ifeq ($(CONFIG_SAB82532),y) -O_OBJS += sab82532.o -else - ifeq ($(CONFIG_SAB82532),m) - M_OBJS += sab82532.o - endif -endif - -ifeq ($(CONFIG_ENVCTRL),y) -O_OBJS += envctrl.o -else - ifeq ($(CONFIG_ENVCTRL),m) - M_OBJS += envctrl.o - endif -endif - -ifeq ($(CONFIG_DISPLAY7SEG),y) -O_OBJS += display7seg.o -else - ifeq ($(CONFIG_DISPLAY7SEG),m) - M_OBJS += display7seg.o - endif -endif - -endif # eq($(CONFIG_PCI,y) - -ifeq ($(CONFIG_OBP_FLASH),y) -O_OBJS += flash.o -else - ifeq ($(CONFIG_OBP_FLASH),m) - M_OBJS += flash.o - endif +OX_OBJS += su.o +O_OBJS += pcikbd.o endif -else # !eq($(ARCH),sparc64) +ifeq ($(ARCH),sparc64) ifeq ($(CONFIG_PCI),y) -OX_OBJS += su.o -O_OBJS += pcikbd.o -endif - -endif # !eq($(ARCH),sparc64) - -ifeq ($(CONFIG_SUN_OPENPROMIO),y) -O_OBJS += openprom.o -else - ifeq ($(CONFIG_SUN_OPENPROMIO),m) - M_OBJS += openprom.o - endif +obj-$(CONFIG_SAB82532) += sab82532.o +obj-$(CONFIG_ENVCTRL) += envctrl.o +obj-$(CONFIG_DISPLAY7SEG) += display7seg.o endif -ifeq ($(CONFIG_SUN_MOSTEK_RTC),y) -O_OBJS += rtc.o -else - ifeq ($(CONFIG_SUN_MOSTEK_RTC),m) - M_OBJS += rtc.o - endif +obj-$(CONFIG_OBP_FLASH) += flash.o endif -ifeq ($(CONFIG_SUN_BPP),y) -O_OBJS += bpp.o -else - ifeq ($(CONFIG_SUN_BPP),m) - M_OBJS += bpp.o - endif -endif - -ifeq ($(CONFIG_SUN_VIDEOPIX),y) -O_OBJS += vfc.o -else - ifeq ($(CONFIG_SUN_VIDEOPIX),m) - M_OBJS += vfc.o - endif -endif +obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o +obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o +obj-$(CONFIG_SUN_BPP) += bpp.o +obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o +obj-$(CONFIG_SUN_AURORA) += aurora.o +obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o +obj-$(CONFIG_SUN_JSFLASH) += jsflash.o -ifeq ($(CONFIG_SUN_AURORA),y) -O_OBJS += aurora.o -else - ifeq ($(CONFIG_SUN_AURORA),m) - M_OBJS += aurora.o - endif -endif - -ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),y) -O_OBJS += uctrl.o -else - ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),m) - M_OBJS += uctrl.o - endif -endif - -ifeq ($(CONFIG_SUN_JSFLASH),y) -O_OBJS += jsflash.o -endif -ifeq ($(CONFIG_SUN_JSFLASH),m) -M_OBJS += jsflash.o -endif +O_OBJS += $(obj-y) +M_OBJS := $(obj-m) include $(TOPDIR)/Rules.make sunkbdmap.o: sunkeymap.c -vfc.o: vfc_dev.o vfc_i2c.o - $(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o +vfc.o: $(vfc-objs) + $(LD) -r -o $@ $(vfc-objs) diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index 133246129..4579404e3 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -1015,7 +1015,7 @@ static inline void freeLptPort(int idx) #endif -static devfs_handle_t devfs_handle = NULL; +static devfs_handle_t devfs_handle; #ifdef MODULE int init_module(void) diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index dbba073de..31c9de932 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,23 +1,29 @@ -/* $Id: envctrl.c,v 1.17 2000/06/19 06:24:47 davem Exp $ +/* $Id: envctrl.c,v 1.18 2000/10/17 16:20:35 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) + * VT - The implementation is to support Sun Microelectronics (SME) platform + * environment monitoring. SME platforms use pcf8584 as the i2c bus + * controller to access pcf8591 (8-bit A/D and D/A converter) and + * pcf8571 (256 x 8-bit static low-voltage RAM with I2C-bus interface). + * At board level, it follows SME Firmware I2C Specification. Reference: + * http://www-eu2.semiconductors.com/pip/PCF8584P + * http://www-eu2.semiconductors.com/pip/PCF8574AP + * http://www-eu2.semiconductors.com/pip/PCF8591P + * */ -#include <linux/version.h> #include <linux/config.h> #include <linux/module.h> - -#define __KERNEL_SYSCALLS__ #include <linux/sched.h> -#include <linux/unistd.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/ioport.h> #include <linux/init.h> -#include <linux/malloc.h> #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mm.h> +#include <linux/malloc.h> #include <asm/ebus.h> #include <asm/uaccess.h> @@ -25,18 +31,6 @@ #define ENVCTRL_MINOR 162 - -#undef U450_SUPPORT /* might fry you machine, careful here !!! */ - - -#undef DEBUG -#undef DEBUG_BUS_SCAN - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) -#define schedule_timeout(a) { current->timeout = jiffies + (a); schedule(); } -#endif - #define PCF8584_ADDRESS 0x55 #define CONTROL_PIN 0x80 @@ -71,1532 +65,879 @@ #define CLK_8 0x18 #define CLK_12 0x1c +#define OBD_SEND_START 0xc5 /* value to generate I2c_bus START condition */ +#define OBD_SEND_STOP 0xc3 /* value to generate I2c_bus STOP condition */ -#define I2C_WRITE 0x00 -#define I2C_READ 0x01 - -/* PCF8584 register offsets */ -#define I2C_DATA 0x00UL -#define I2C_CSR 0x01UL -#define I2C_REG_SIZE 0x02UL - -struct i2c_device { - unsigned char addr; - struct i2c_device *next; -}; - -static unsigned long i2c_regs; -static struct i2c_device *i2c_devices; - -static int errno; - -#define MAX_TEMPERATURE 111 -#define MAX_FAN_SPEED 63 - - -/* - * UltraAXi constants. +/* Monitor type of i2c child device. + * Firmware definitions. */ -#define AXI_THERM_ADDR 0x9e -#define AXI_THERM_PORT_CPU 0 -#define AXI_THERM_PORT_MOD 1 -#define AXI_THERM_PORT_PCI 2 -#define AXI_THERM_PORT_DISK 3 - -#define AXI_FAN_ADDR 0x4e -#define AXI_FAN_PORT_FRONT 0 -#define AXI_FAN_PORT_BACK 1 - -#define AXI_PIO_ADDR 0x70 +#define PCF8584_MAX_CHANNELS 8 +#define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */ +#define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */ +#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/ -/* - * Ultra 450 constants. +/* Monitor type of i2c child device. + * Driver definitions. */ -#define U450_FAN_ADDR 0x4e -#define U450_FAN_PORT_CPU 0 -#define U450_FAN_PORT_PS 1 - -#define U450_PIO_ADDR 0x70 -#define U450_TIMER_ADDR 0xa0 - -static unsigned char -axi_cpu_temp_table[256] = -{ - 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, - 0x66, 0x65, 0x64, 0x63, 0x61, 0x60, 0x5f, 0x5e, - 0x5d, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x55, 0x54, - 0x53, 0x52, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, 0x4a, - 0x49, 0x48, 0x47, 0x46, 0x44, 0x43, 0x42, 0x41, - 0x40, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, - 0x3a, 0x39, 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, - 0x36, 0x35, 0x35, 0x34, 0x34, 0x33, 0x33, 0x32, - 0x32, 0x31, 0x31, 0x30, 0x30, 0x2f, 0x2f, 0x2e, - 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, 0x2b, 0x2a, 0x2a, - 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, 0x26, 0x26, - 0x25, 0x25, 0x24, 0x24, 0x23, 0x23, 0x22, 0x22, - 0x21, 0x21, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x18, - 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, - 0x15, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, - 0x13, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, - 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, - 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, - 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char -axi_mod_temp_table[256] = -{ - 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, - 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, - 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, - 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, - 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, - 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, - 0x35, 0x35, 0x34, 0x34, 0x33, 0x33, 0x32, 0x32, - 0x31, 0x31, 0x30, 0x30, 0x2f, 0x2f, 0x2e, 0x2e, - 0x2e, 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, 0x2b, 0x2a, - 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, - 0x26, 0x26, 0x25, 0x25, 0x24, 0x24, 0x23, 0x23, - 0x23, 0x22, 0x22, 0x21, 0x21, 0x20, 0x20, 0x1f, - 0x1f, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x19, 0x19, - 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, - 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, - 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, - 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, - 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, - 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char -axi_fan_speeds[112] = -{ - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, - 0x22, 0x23, 0x25, 0x27, 0x28, 0x2a, 0x2b, 0x2d, - 0x2f, 0x30, 0x32, 0x33, 0x35, 0x37, 0x38, 0x3a, - 0x3b, 0x3d, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f -}; - - -struct therm_regs { - u32 addr; - u32 port; - u32 min_temp; - u32 warning; - u32 shutdown; - u32 num; - u32 den; -}; +#define ENVCTRL_NOMON 0 +#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ +#define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */ +#define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */ +#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */ + /* monitor */ +#define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */ +#define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */ +#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */ + +/* Child device type. + * Driver definitions. + */ +#define I2C_ADC 0 /* pcf8591 */ +#define I2C_GPIO 1 /* pcf8571 */ -struct thermistor { - char name[8]; - struct therm_regs regs; - unsigned char (*temperature) (struct thermistor *); - unsigned char (*fan_speed) (struct thermistor *); - struct thermistor *next; /* all thermistors */ - struct thermistor *chain; /* thermistors for one fan */ +/* Data read from child device may need to decode + * through a data table and a scale. + * Translation type as defined by firmware. + */ +#define ENVCTRL_TRANSLATE_NO 0 +#define ENVCTRL_TRANSLATE_PARTIAL 1 +#define ENVCTRL_TRANSLATE_COMBINED 2 +#define ENVCTRL_TRANSLATE_FULL 3 /* table[data] */ +#define ENVCTRL_TRANSLATE_SCALE 4 /* table[data]/scale */ + +/* Driver miscellaneous definitions. */ +#define ENVCTRL_MAX_CPU 4 +#define CHANNEL_DESC_SZ 256 + +struct pcf8584_reg { + unsigned char data; + unsigned char csr; }; -struct fan_regs { - u32 addr; - u32 port; +/* Each child device can be monitored by up to PCF8584_MAX_CHANNELS. + * Property of a port or channel as defined by the firmware. + */ +struct pcf8584_channel { + unsigned char chnl_no; + unsigned char io_direction; + unsigned char type; + unsigned char last; }; -struct fan { - char name[8]; - struct fan_regs regs; - int (*set_speed)(struct fan *, unsigned char value); - int (*check_failure)(struct fan *); - unsigned char value; - struct thermistor *monitor; - struct fan *next; +/* Each child device may have one or more tables of bytes to help decode + * data. Table property as defined by the firmware. + */ +struct pcf8584_tblprop { + unsigned int type; + unsigned int scale; + unsigned int offset; /* offset from the beginning of the table */ + unsigned int size; }; - -struct environment { - struct thermistor *thermistors; - struct fan *fans; - unsigned char *cpu_temp_table; - unsigned char *cpu_fan_speeds; - unsigned char *ps_temp_table; - unsigned char *ps_fan_speeds; - void (*enable) (struct environment *); - void (*disable) (struct environment *); - void (*keep_alive) (struct environment *); - int interval; - pid_t kenvd_pid; - wait_queue_head_t kenvd_wait; - int terminate; +/* i2c child */ +struct i2c_child_t { + /* Either ADC or GPIO. */ + unsigned char i2ctype; + unsigned long addr; + struct pcf8584_channel chnl_array[PCF8584_MAX_CHANNELS]; + + /* Channel info. */ + unsigned int total_chnls; /* Number of monitor channels. */ + unsigned char fan_mask; /* Byte mask for fan status channels. */ + unsigned char voltage_mask; /* Byte mask for voltage status channels. */ + struct pcf8584_tblprop tblprop_array[PCF8584_MAX_CHANNELS]; + + /* Properties of all monitor channels. */ + unsigned int total_tbls; /* Number of monitor tables. */ + char *tables; /* Pointer to table(s). */ + char chnls_desc[CHANNEL_DESC_SZ]; /* Channel description. */ + char mon_type[PCF8584_MAX_CHANNELS]; }; +volatile static struct pcf8584_reg *i2c = NULL; +static struct i2c_child_t i2c_childlist[ENVCTRL_MAX_CPU*2]; +static unsigned char chnls_mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; +static unsigned int warning_temperature = 0; +static unsigned int shutdown_temperature = 0; +static char read_cpu; -static struct environment envctrl; - +/* Forward declarations. */ +static struct i2c_child_t *envctrl_get_i2c_child(unsigned char); -#ifdef DEBUG_BUS_SCAN -struct i2c_addr_map { - unsigned char addr; - unsigned char mask; - char *name; -}; - -static struct i2c_addr_map devmap[] = { - { 0x70, 0xf0, "PCF8574A" }, - { 0x40, 0xf0, "TDA8444" }, - { 0x90, 0xf0, "PCF8591" }, - { 0xa0, 0xf0, "PCF8583" }, -}; -#define NR_DEVMAP (sizeof(devmap) / sizeof(devmap[0])) -#endif - -static __inline__ int -PUT_DATA(unsigned long data, char *buffer, int user) +/* Function description: Read a byte from an i2c controller register. + * Return: A byte from the passed in address. + */ +static inline unsigned char envctrl_readb(volatile unsigned char *p) { - if (user) { - u8 tmp = readb(data); - if (put_user(tmp, buffer)) - return -EFAULT; - } else { - *buffer = readb(data); - } - return 0; + return readb(p); } -static __inline__ int -GET_DATA(unsigned long data, const char *buffer, int user) +/* Function description: Write a byte to an i2c controller register. + * Return: Nothing. + */ +static inline void envctrl_writeb(unsigned char val, volatile unsigned char *p) { - if (user) { - u8 tmp; - if (get_user(tmp, buffer)) - return -EFAULT; - writeb(tmp, data); - } else { - writeb(*buffer, data); - } - return 0; + writeb(val, p); } - -static int -i2c_read(unsigned char dev, char *buffer, int len, int user) +/* Function Description: Test the PIN bit (Pending Interrupt Not) + * to test when serial transmission is completed . + * Return : None. + */ +static void envtrl_i2c_test_pin(void) { - unsigned char dummy; - unsigned char stat; - int error = -ENODEV; - int count = 0; - - writeb((dev & 0xfe) | I2C_READ, i2c_regs + I2C_DATA); - - while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB)) - udelay(1); - - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, - i2c_regs + I2C_CSR); - - do { - udelay(1); - while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) - udelay(1); - - if (stat & STATUS_LRB) - goto stop; + int limit = 1000000; - error = 0; - if (len == 0) { - count--; + while (--limit > 0) { + if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) break; - } - - if (count == (len - 1)) - break; - - if (count++ > 0) { - error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); - if (error) - break; - } else - dummy = readb(i2c_regs + I2C_DATA); - } while (1); - - writeb(CONTROL_ES0, i2c_regs + I2C_CSR); - if (!error && (count++ > 0)) - error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); - else - dummy = readb(i2c_regs + I2C_DATA); - - udelay(1); - while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) udelay(1); + } -stop: - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, - i2c_regs + I2C_CSR); - if (!error && (count++ > 0)) - error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); - else - dummy = readb(i2c_regs + I2C_DATA); - - if (error) - return error; - return count - 1; + if (limit <= 0) + printk(KERN_INFO "envctrl: Pin status will not clear.\n"); } -static int -i2c_write(unsigned char dev, const char *buffer, int len, int user) +/* Function Description: Test busy bit. + * Return : None. + */ +static void envctrl_i2c_test_bb(void) { - int error = -ENODEV; - int count = 0; - int timeout; - - timeout = 1000000; - while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB) && --timeout) - udelay(1); - if (!timeout) { - printk("%s [%d]: TIMEOUT\n", __FUNCTION__, __LINE__); - return -ENODEV; - } - - writeb((dev & 0xfe) | I2C_WRITE, i2c_regs + I2C_DATA); - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, - i2c_regs + I2C_CSR); - - do { - unsigned char stat; - - udelay(1); - timeout = 1000000; - while (((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) && --timeout) - udelay(1); - - if (!timeout) { - printk("%s [%d]: TIMEOUT\n", __FUNCTION__, __LINE__); - break; - } + int limit = 1000000; - if (stat & STATUS_LRB) + while (--limit > 0) { + /* Busy bit 0 means busy. */ + if (envctrl_readb(&i2c->csr) & STATUS_BB) break; + udelay(1); + } - error = count; - if (count == len) - break; - - error = GET_DATA(i2c_regs + I2C_DATA, buffer++, user); - if (error) - break; - - count++; - } while (1); - - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, - i2c_regs + I2C_CSR); - return error; + if (limit <= 0) + printk(KERN_INFO "envctrl: Busy bit will not clear.\n"); } -#ifdef U450_SUPPORT -static int -i2c_write_read(unsigned char dev, char *outbuf, int outlen, - char *inbuf, int inlen, int user) +/* Function Description: Send the adress for a read access. + * Return : 0 if not acknowledged, otherwise acknowledged. + */ +static int envctrl_i2c_read_addr(unsigned char addr) { - unsigned char dummy; - unsigned char stat; - int error = -ENODEV; - int count = 0; - - while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB)) - udelay(1); - - writeb((dev & 0xfe) | I2C_WRITE, i2c_regs + I2C_DATA); - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, - i2c_regs + I2C_CSR); - - do { - unsigned char stat; - - udelay(1); - while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) - udelay(1); + envctrl_i2c_test_bb(); - if (stat & STATUS_LRB) - break; + /* Load address. */ + envctrl_writeb(addr + 1, &i2c->data); - error = count; - if (count == outlen) - break; + envctrl_i2c_test_bb(); - error = GET_DATA(i2c_regs + I2C_DATA, outbuf++, user); - if (error) - break; + envctrl_writeb(OBD_SEND_START, &i2c->csr); - count++; - } while (1); + /* Wait for PIN. */ + envtrl_i2c_test_pin(); - if (error < 0) { - writeb(CONTROL_PIN | CONTROL_ES0 | - CONTROL_STO | CONTROL_ACK, i2c_regs + I2C_CSR); - return error; + /* CSR 0 means acknowledged. */ + if (!(envctrl_readb(&i2c->csr) & STATUS_LRB)) { + return envctrl_readb(&i2c->data); + } else { + envctrl_writeb(OBD_SEND_STOP, &i2c->csr); + return 0; } - - writeb(CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, i2c_regs + I2C_CSR); - udelay(1); - writeb((dev & 0xfe) | I2C_READ, i2c_regs + I2C_DATA); - - count = 0; - do { - udelay(1); - while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) - udelay(1); - - if (stat & STATUS_LRB) - goto stop; - - error = 0; - if (inlen == 0) { - count--; - break; - } - - if (count == (inlen - 1)) - break; - - if (count++ > 0) { - error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); - if (error) - break; - } else - dummy = readb(i2c_regs + I2C_DATA); - } while (1); - - writeb(CONTROL_ES0, i2c_regs + I2C_CSR); - if (!error && (count++ > 0)) - error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); - else - dummy = readb(i2c_regs + I2C_DATA); - - udelay(1); - while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) - udelay(1); - -stop: - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, - i2c_regs + I2C_CSR); - if (!error && (count++ > 0)) - error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); - else - dummy = readb(i2c_regs + I2C_DATA); - - if (error) - return error; - return count - 1; } -#endif /* U450_SUPPORT */ -static struct i2c_device * -i2c_find_device(unsigned char addr) +/* Function Description: Send the adress for write mode. + * Return : None. + */ +static void envctrl_i2c_write_addr(unsigned char addr) { - struct i2c_device *dev; + envctrl_i2c_test_bb(); + envctrl_writeb(addr, &i2c->data); - for (dev = i2c_devices; dev; dev = dev->next) { - if (dev->addr == addr) - return dev; - } - return 0; + /* Generate Start condition. */ + envctrl_writeb(OBD_SEND_START, &i2c->csr); } -static void -i2c_free_devices(void) +/* Function Description: Read 1 byte of data from addr + * set by envctrl_i2c_read_addr() + * Return : Data from address set by envctrl_i2c_read_addr(). + */ +static unsigned char envctrl_i2c_read_data(void) { - struct i2c_device *dev; - - dev = i2c_devices; - while (dev) { - i2c_devices = dev->next; - kfree(dev); - dev = i2c_devices; - } + envtrl_i2c_test_pin(); + envctrl_writeb(CONTROL_ES0, &i2c->csr); /* Send neg ack. */ + return envctrl_readb(&i2c->data); } -static __init int i2c_scan_bus(void) +/* Function Description: Instruct the device which port to read data from. + * Return : None. + */ +static void envctrl_i2c_write_data(unsigned char port) { - struct i2c_device *dev, **last; - unsigned int addr; - int count = 0; - - last = &i2c_devices; - for (addr = 0; addr < 256; addr += 2) { - if (i2c_write(addr, 0, 0, 0) == 0) { -#ifdef DEBUG_BUS_SCAN - int i; - for (i = 0; i < NR_DEVMAP; i++) - if ((addr & devmap[i].mask) == devmap[i].addr) - break; - printk("envctrl: i2c device at %02x: %s\n", addr, - i < NR_DEVMAP ? devmap[i].name : "unknown"); -#endif - - dev = kmalloc(sizeof(struct i2c_device), GFP_KERNEL); - if (!dev) { - printk("i2c: can't alloc i2c_device\n"); - i2c_free_devices(); - return -ENOMEM; - } - memset(dev, 0, sizeof(struct i2c_device)); - - dev->addr = addr; - - *last = dev; - last = &dev->next; - - count++; - } - } - if (!count) { - printk("%s: no devices found\n", __FUNCTION__); - return -ENODEV; - } - return 0; + envtrl_i2c_test_pin(); + envctrl_writeb(port, &i2c->data); } - -static int -read_8591(unsigned char dev, unsigned char offset, unsigned char *value) +/* Function Description: Generate Stop condition after last byte is sent. + * Return : None. + */ +static void envctrl_i2c_stop(void) { - unsigned char data[2]; - - data[0] = 0x40 | offset; - if (i2c_write(dev, data, 1, 0) != 1) - return -1; - if (i2c_read(dev, data, 2, 0) != 2) - return -1; - *value = data[1]; - return 0; + envtrl_i2c_test_pin(); + envctrl_writeb(OBD_SEND_STOP, &i2c->csr); } -static int -write_8444(unsigned char dev, unsigned char offset, unsigned char value) +/* Function Description: Read adc device. + * Return : Data at address and port. + */ +static unsigned char envctrl_i2c_read_8591(unsigned char addr, unsigned char port) { - unsigned char data[2]; + /* Send address. */ + envctrl_i2c_write_addr(addr); - data[0] = offset; - data[1] = value; - if (i2c_write(dev, data, 2, 0) != 2) - return -1; - return 0; -} + /* Setup port to read. */ + envctrl_i2c_write_data(port); + envctrl_i2c_stop(); -#ifdef U450_SUPPORT -static int -read_8583(unsigned char dev, unsigned char offset, unsigned char *value) -{ - unsigned char data; + /* Read port. */ + envctrl_i2c_read_addr(addr); - data = offset; - if (i2c_write_read(dev, &data, 1, &data, 1, 0) != 1) - return -1; - *value = data; - return 0; -} - -static int -write_8583(unsigned char dev, unsigned char offset, unsigned char value) -{ - unsigned char data[2]; + /* Do a single byte read and send stop. */ + envctrl_i2c_read_data(); + envctrl_i2c_stop(); - data[0] = offset; - data[1] = value; - if (i2c_write(dev, data, 2, 0) != 2) - return -1; - return 0; + return envctrl_readb(&i2c->data); } -#endif /* U450_SUPPORT */ -struct thermistor * -find_thermistor(const char *name, struct thermistor *from) +/* Function Description: Read gpio device. + * Return : Data at address. + */ +static unsigned char envctrl_i2c_read_8574(unsigned char addr) { - int n; + unsigned char rd; - if (!from) - from = envctrl.thermistors; - else - from = from->next; + envctrl_i2c_read_addr(addr); - n = strlen(name); - while (from && strncmp(from->name, name, n)) - from = from->next; + /* Do a single byte read and send stop. */ + rd = envctrl_i2c_read_data(); + envctrl_i2c_stop(); - return from; + return rd; } -void -check_temperatures(struct environment *env) +/* Function Description: Decode data read from an adc device using firmware + * table. + * Return: Number of read bytes. Data is stored in bufdata in ascii format. + */ +static int envctrl_i2c_data_translate(unsigned char data, int translate_type, + int scale, char *tbl, char *bufdata) { - struct thermistor *t; - - for (t = env->thermistors; t; t = t->next) { -#ifdef DEBUG - printk("Thermistor `%s' [%02x:%d]: " - "%d C (%d C, %d C)\n", - t->name, t->regs.addr, t->regs.port, - t->temperature(t), t->regs.warning, t->regs.shutdown); -#endif + int len = 0; - /* - * Implement slow-down or shutdown here... - */ - } -} + switch (translate_type) { + case ENVCTRL_TRANSLATE_NO: + /* No decode necessary. */ + len = 1; + bufdata[0] = data; + break; -void -check_fan_speeds(struct environment *env) -{ - unsigned char speed, max; - struct thermistor *t; - struct fan *f; - - for (f = env->fans; f; f = f->next) { -#ifdef DEBUG - printk("Fan `%s' [%02x:%d]:", f->name, - f->regs.addr, f->regs.port); -#endif - max = 0; - for (t = f->monitor; t; t = t->chain) { - speed = t->fan_speed(t); - if (speed > max) - max = speed; -#ifdef DEBUG - printk(" %s:%02x", t->name, speed); -#endif - } + case ENVCTRL_TRANSLATE_FULL: + /* Decode this way: data = table[data]. */ + len = 1; + bufdata[0] = tbl[data]; + break; - f->set_speed(f, max); -#ifdef DEBUG - printk(" -> %02x\n", f->value); -#endif - } -} + case ENVCTRL_TRANSLATE_SCALE: + /* Decode this way: data = table[data]/scale */ + sprintf(bufdata,"%d ", (tbl[data] * 10) / (scale)); + len = strlen(bufdata); + bufdata[len - 1] = bufdata[len - 2]; + bufdata[len - 2] = '.'; + break; -void -envctrl_fans_blast(struct environment *env) -{ - struct fan *f; + default: + break; + }; - for (f = env->fans; f; f = f->next) - f->set_speed(f, MAX_FAN_SPEED); + return len; } -int -kenvd(void *data) +/* Function Description: Read cpu-related data such as cpu temperature, voltage. + * Return: Number of read bytes. Data is stored in bufdata in ascii format. + */ +static int envctrl_read_cpu_info(struct i2c_child_t *pchild, + char mon_type, unsigned char *bufdata) { - struct environment *env = data; - - MOD_INC_USE_COUNT; - lock_kernel(); - - env->kenvd_pid = current->pid; - - exit_files(current); - exit_mm(current); - - spin_lock_irq(¤t->sigmask_lock); - siginitsetinv(¤t->blocked, sigmask(SIGKILL)); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - current->session = 1; - current->pgrp = 1; - strcpy(current->comm, "kenvd"); - - if (env->enable) - env->enable(env); - - while (!env->terminate) { - - check_temperatures(env); - check_fan_speeds(env); - if (env->keep_alive) - env->keep_alive(env); - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(env->interval * HZ); + unsigned char data; + int i; + char *tbl, j = -1; - if (signal_pending(current)) { - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); - break; + /* Find the right monitor type and channel. */ + for (i = 0; i < PCF8584_MAX_CHANNELS; i++) { + if (pchild->mon_type[i] == mon_type) { + if (++j == read_cpu) { + break; + } } } - if (env->disable) - env->disable(env); + if (j != read_cpu) + return 0; - env->kenvd_pid = 0; - wake_up(&envctrl.kenvd_wait); + /* Read data from address and port. */ + data = envctrl_i2c_read_8591((unsigned char)pchild->addr, + (unsigned char)pchild->chnl_array[i].chnl_no); - MOD_DEC_USE_COUNT; - return 0; -} + /* Find decoding table. */ + tbl = pchild->tables + pchild->tblprop_array[i].offset; -void -envctrl_stop(void) -{ - DECLARE_WAITQUEUE(wait, current); - struct thermistor *t; - struct fan *f; - pid_t pid; - - if (envctrl.kenvd_pid) { - pid = envctrl.kenvd_pid; - - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&envctrl.kenvd_wait, &wait); - - envctrl.terminate = 1; - kill_proc(pid, SIGKILL, 1); - - schedule(); - - remove_wait_queue(&envctrl.kenvd_wait, &wait); - current->state = TASK_RUNNING; - } - - t = envctrl.thermistors; - while (t) { - envctrl.thermistors = t->next; - kfree(t); - t = envctrl.thermistors; - } - - f = envctrl.fans; - while (f) { - envctrl.fans = f->next; - kfree(f); - f = envctrl.fans; - } - - if (envctrl.cpu_temp_table) - kfree(envctrl.cpu_temp_table); - - if (envctrl.cpu_fan_speeds) - kfree(envctrl.cpu_fan_speeds); - - if (envctrl.ps_temp_table) - kfree(envctrl.ps_temp_table); - - if (envctrl.ps_fan_speeds) - kfree(envctrl.ps_fan_speeds); -} - - -static unsigned char -axi_get_temperature(struct thermistor *t) -{ - unsigned char value; - - if (read_8591(t->regs.addr, t->regs.port, &value) < 0) - return MAX_TEMPERATURE; - if (t->regs.port == AXI_THERM_PORT_CPU) - return axi_cpu_temp_table[value]; - else - return axi_mod_temp_table[value]; + return envctrl_i2c_data_translate(data, pchild->tblprop_array[i].type, + pchild->tblprop_array[i].scale, + tbl, bufdata); } -static unsigned char -axi_get_fan_speed(struct thermistor *t) +/* Function Description: Read noncpu-related data such as motherboard + * temperature. + * Return: Number of read bytes. Data is stored in bufdata in ascii format. + */ +static int envctrl_read_noncpu_info(struct i2c_child_t *pchild, + char mon_type, unsigned char *bufdata) { - unsigned char temp; - - temp = t->temperature(t); - if (temp >= MAX_TEMPERATURE) - return MAX_FAN_SPEED; - - return axi_fan_speeds[temp]; -} + unsigned char data; + int i; + char *tbl = NULL; -static int -axi_set_fan_speed(struct fan *f, unsigned char value) -{ - if (value != f->value) { - if (write_8444(f->regs.addr, f->regs.port, value)) - return -1; - f->value = value; + for (i = 0; i < PCF8584_MAX_CHANNELS; i++) { + if (pchild->mon_type[i] == mon_type) + break; } - return 0; -} -static void -axi_toggle_i2c_int(struct environment *env) -{ - unsigned char data; + if (i >= PCF8584_MAX_CHANNELS) + return 0; - if (i2c_read(AXI_PIO_ADDR, &data, 1, 0) != 1) - return; + /* Read data from address and port. */ + data = envctrl_i2c_read_8591((unsigned char)pchild->addr, + (unsigned char)pchild->chnl_array[i].chnl_no); - data &= ~(0x08); - if (i2c_write(AXI_PIO_ADDR, &data, 1, 0) != 1) - return; - mdelay(1); + /* Find decoding table. */ + tbl = pchild->tables + pchild->tblprop_array[i].offset; - data |= 0x08; - if (i2c_write(AXI_PIO_ADDR, &data, 1, 0) != 1) - return; - mdelay(1); + return envctrl_i2c_data_translate(data, pchild->tblprop_array[i].type, + pchild->tblprop_array[i].scale, + tbl, bufdata); } - -static int -rasctrl_setup(int node) +/* Function Description: Read fan status. + * Return : Always 1 byte. Status stored in bufdata. + */ +static int envctrl_i2c_fan_status(struct i2c_child_t *pchild, + unsigned char data, + char *bufdata) { - struct thermistor *t, **tlast; - struct fan *f, **flast; - char tmp[32]; - int monitor; - int shutdown; - int warning; - int i; + unsigned char tmp, ret = 0; + int i, j = 0; - prom_getstring(prom_root_node, "name", tmp, sizeof(tmp)); - if (strcmp(tmp, "SUNW,UltraSPARC-IIi-Engine")) { - printk("SUNW,rasctrl will work only on Ultra AXi\n"); - return -ENODEV; - } + tmp = data & pchild->fan_mask; - monitor = prom_getintdefault(node, "env-monitor", 0); - if (monitor == 0) - return -ENODEV; + if (tmp == pchild->fan_mask) { + /* All bits are on. All fans are functioning. */ + ret = ENVCTRL_ALL_FANS_GOOD; + } else if (tmp == 0) { + /* No bits are on. No fans are functioning. */ + ret = ENVCTRL_ALL_FANS_BAD; + } else { + /* Go through all channels, mark 'on' the matched bits. + * Notice that fan_mask may have discontiguous bits but + * return mask are always contiguous. For example if we + * monitor 4 fans at channels 0,1,2,4, the return mask + * should be 00010000 if only fan at channel 4 is working. + */ + for (i = 0; i < PCF8584_MAX_CHANNELS;i++) { + if (pchild->fan_mask & chnls_mask[i]) { + if (!(chnls_mask[i] & tmp)) + ret |= chnls_mask[j]; - envctrl.interval = prom_getintdefault(node, "env-mon-interval", 60); - warning = prom_getintdefault(node, "warning-temp", 55); - shutdown = prom_getintdefault(node, "shutdown-temp", 58); - - tlast = &envctrl.thermistors; - for (i = 0; i < 4; i++) { - t = kmalloc(sizeof(struct thermistor), GFP_KERNEL); - if (!t) - goto out; - memset(t, 0, sizeof(struct thermistor)); - - t->regs.addr = AXI_THERM_ADDR; - t->regs.port = i; - t->regs.warning = warning; - t->regs.shutdown = shutdown; - - switch (i) { - case AXI_THERM_PORT_CPU: - sprintf(t->name, "%.7s", "CPU"); - break; - case AXI_THERM_PORT_MOD: - sprintf(t->name, "%.7s", "MOD"); - break; - case AXI_THERM_PORT_PCI: - sprintf(t->name, "%.7s", "PCI"); - break; - case AXI_THERM_PORT_DISK: - sprintf(t->name, "%.7s", "DISK"); - break; + j++; + } } + } - t->temperature = axi_get_temperature; - t->fan_speed = axi_get_fan_speed; + bufdata[0] = ret; + return 1; +} - if (!i2c_find_device(t->regs.addr)) { - printk("envctrl: `%s': i2c device %02x not found\n", - t->name, t->regs.addr); - kfree(t); - continue; +/* Function Description: Read voltage and power supply status. + * Return : Always 1 byte. Status stored in bufdata. + */ +static unsigned char envctrl_i2c_voltage_status(struct i2c_child_t *pchild, + unsigned char data, + char *bufdata) +{ + unsigned char tmp, ret = 0; + int i, j = 0; + + tmp = data & pchild->voltage_mask; + + /* Two channels are used to monitor voltage and power supply. */ + if (tmp == pchild->voltage_mask) { + /* All bits are on. Voltage and power supply are okay. */ + ret = ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD; + } else if (tmp == 0) { + /* All bits are off. Voltage and power supply are bad */ + ret = ENVCTRL_VOLTAGE_POWERSUPPLY_BAD; + } else { + /* Either voltage or power supply has problem. */ + for (i = 0; i < PCF8584_MAX_CHANNELS; i++) { + if (pchild->voltage_mask & chnls_mask[i]) { + j++; + + /* Break out when there is a mismatch. */ + if (!(chnls_mask[i] & tmp)) + break; + } } - *tlast = t; - tlast = &t->next; + /* Make a wish that hardware will always use the + * first channel for voltage and the second for + * power supply. + */ + if (j == 1) + ret = ENVCTRL_VOLTAGE_BAD; + else + ret = ENVCTRL_POWERSUPPLY_BAD; } - flast = &envctrl.fans; - for (i = 0; i < 2; i++) { - f = kmalloc(sizeof(struct fan), GFP_KERNEL); - if (!f) - goto out; - memset(f, 0, sizeof(struct fan)); - - f->regs.addr = AXI_FAN_ADDR; - f->regs.port = i; - - switch (i) { - case AXI_FAN_PORT_FRONT: - sprintf(f->name, "%.7s", "FRONT"); - t = NULL; - while ((t = find_thermistor("CPU", t))) { - t->chain = f->monitor; - f->monitor = t; - } - break; - case AXI_FAN_PORT_BACK: - sprintf(f->name, "%.7s", "BACK"); - t = NULL; - while ((t = find_thermistor("PCI", t))) { - t->chain = f->monitor; - f->monitor = t; - } - break; - } + bufdata[0] = ret; + return 1; +} - if (!f->monitor) { - kfree(f); - continue; - } +/* Function Description: Read a byte from /dev/envctrl. Mapped to user read(). + * Return: Number of read bytes. 0 for error. + */ +static ssize_t +envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct i2c_child_t *pchild; + unsigned char data[10]; + int ret = 0; + + /* Get the type of read as decided in ioctl() call. + * Find the appropriate i2c child. + * Get the data and put back to the user buffer. + */ + + switch ((int)(long)file->private_data) { + case ENVCTRL_RD_WARNING_TEMPERATURE: + if (warning_temperature == 0) + return 0; + + data[0] = (unsigned char)(warning_temperature); + ret = 1; + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_SHUTDOWN_TEMPERATURE: + if (shutdown_temperature == 0) + return 0; + + data[0] = (unsigned char)(shutdown_temperature); + ret = 1; + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_MTHRBD_TEMPERATURE: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_MTHRBDTEMP_MON))) + return 0; + ret = envctrl_read_noncpu_info(pchild, ENVCTRL_MTHRBDTEMP_MON, data); + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_CPU_TEMPERATURE: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) + return 0; + ret = envctrl_read_cpu_info(pchild, ENVCTRL_CPUTEMP_MON, data); + + /* Reset cpu to the default cpu0. */ + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_CPU_VOLTAGE: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_CPUVOLTAGE_MON))) + return 0; + ret = envctrl_read_cpu_info(pchild, ENVCTRL_CPUVOLTAGE_MON, data); + + /* Reset cpu to the default cpu0. */ + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_SCSI_TEMPERATURE: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_SCSITEMP_MON))) + return 0; + ret = envctrl_read_noncpu_info(pchild, ENVCTRL_SCSITEMP_MON, data); + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_ETHERNET_TEMPERATURE: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_ETHERTEMP_MON))) + return 0; + ret = envctrl_read_noncpu_info(pchild, ENVCTRL_ETHERTEMP_MON, data); + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_FAN_STATUS: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_FANSTAT_MON))) + return 0; + data[0] = envctrl_i2c_read_8574(pchild->addr); + ret = envctrl_i2c_fan_status(pchild,data[0], data); + copy_to_user((unsigned char *)buf, data, ret); + break; + + case ENVCTRL_RD_VOLTAGE_STATUS: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON))) + return 0; + data[0] = envctrl_i2c_read_8574(pchild->addr); + ret = envctrl_i2c_voltage_status(pchild, data[0], data); + copy_to_user((unsigned char *)buf, data, ret); + break; + + default: + break; + + }; + + return ret; +} + +/* Function Description: Command what to read. Mapped to user ioctl(). + * Return: Gives 0 for implemented commands, -EINVAL otherwise. + */ +static int +envctrl_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + char *infobuf; - if (!i2c_find_device(f->regs.addr)) { - printk("envctrl: `%s': i2c device %02x not found\n", - f->name, f->regs.addr); - kfree(f); - continue; + switch (cmd) { + case ENVCTRL_RD_WARNING_TEMPERATURE: + case ENVCTRL_RD_SHUTDOWN_TEMPERATURE: + case ENVCTRL_RD_MTHRBD_TEMPERATURE: + case ENVCTRL_RD_FAN_STATUS: + case ENVCTRL_RD_VOLTAGE_STATUS: + case ENVCTRL_RD_ETHERNET_TEMPERATURE: + case ENVCTRL_RD_SCSI_TEMPERATURE: + file->private_data = (void *)(long)cmd; + break; + + case ENVCTRL_RD_CPU_TEMPERATURE: + case ENVCTRL_RD_CPU_VOLTAGE: + /* Check to see if application passes in any cpu number, + * the default is cpu0. + */ + infobuf = (char *) arg; + if (infobuf == NULL) { + read_cpu = 0; + }else { + get_user(read_cpu, infobuf); } - *flast = f; - flast = &f->next; + /* Save the command for use when reading. */ + file->private_data = (void *)(long)cmd; + break; - f->check_failure = NULL; - f->set_speed = axi_set_fan_speed; - } - - envctrl.enable = axi_toggle_i2c_int; - envctrl.disable = envctrl_fans_blast; + default: + return -EINVAL; + }; -#ifdef DEBUG - printk("Warn: %d C, Shutdown %d C, Interval %d s, Monitor %d\n", - warning, shutdown, envctrl.interval, monitor); -#endif return 0; - -out: - return -ENODEV; -} - - -#ifdef U450_SUPPORT - -static unsigned char -envctrl_get_temperature(struct thermistor *t) -{ - unsigned char value; - - if (read_8591(t->regs.addr, t->regs.port, &value) < 0) - return MAX_TEMPERATURE; - if (!strncmp(t->name, "CPU", 3)) - return envctrl.cpu_temp_table[value]; - else - return envctrl.ps_temp_table[value]; } -static unsigned char -envctrl_get_fan_speed(struct thermistor *t) +/* Function Description: open device. Mapped to user open(). + * Return: Always 0. + */ +static int +envctrl_open(struct inode *inode, struct file *file) { - unsigned char temp; - - temp = t->temperature(t); - if (temp >= MAX_TEMPERATURE) - return MAX_FAN_SPEED; - - if (!strncmp(t->name, "CPU", 3)) - return envctrl.cpu_fan_speeds[temp]; - else - return envctrl.ps_fan_speeds[temp]; + file->private_data = 0; + MOD_INC_USE_COUNT; + return 0; } +/* Function Description: Open device. Mapped to user close(). + * Return: Always 0. + */ static int -envctrl_set_fan_speed(struct fan *f, unsigned char value) +envctrl_release(struct inode *inode, struct file *file) { - if (value != f->value) { - if (write_8444(f->regs.addr, f->regs.port, value)) - return -1; - f->value = value; - } - + MOD_DEC_USE_COUNT; return 0; } -static unsigned char u450_default_thermisters[] = -{ - /* CPU0 */ - 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x30, 0x00, - /* CPU1 */ - 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x31, 0x00, - /* CPU2 */ - 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x32, 0x00, - /* CPU3 */ - 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x33, 0x00, - /* PS0 */ - 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x30, 0x00, - /* PS1 */ - 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x31, 0x00, - /* PS2 */ - 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x32, 0x00, - /* AMB */ - 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x42, 0x00 -}; - -static unsigned char u450_default_cpu_temp_factors[] = -{ - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x94, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, - 0x8a, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, - 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, - 0x79, 0x79, 0x78, 0x78, 0x77, 0x76, 0x75, 0x74, - 0x73, 0x72, 0x71, 0x70, 0x70, 0x6f, 0x6f, 0x6e, - 0x6e, 0x6e, 0x6d, 0x6d, 0x6c, 0x6b, 0x6a, 0x6a, - 0x69, 0x69, 0x68, 0x67, 0x66, 0x65, 0x65, 0x64, - 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, - 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, - 0x5c, 0x5c, 0x5b, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, - 0x59, 0x59, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, - 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x52, 0x52, - 0x52, 0x51, 0x51, 0x50, 0x50, 0x50, 0x50, 0x4f, - 0x4f, 0x4f, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, - 0x4c, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, - 0x4a, 0x49, 0x49, 0x49, 0x48, 0x48, 0x48, 0x47, - 0x47, 0x47, 0x46, 0x46, 0x46, 0x46, 0x45, 0x45, - 0x45, 0x44, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, - 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, - 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, - 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, - 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, - 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, - 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x33, 0x32, - 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, - 0x2f, 0x2f, 0x2f, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, - 0x2d, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2a, - 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28 -}; - -static unsigned char u450_default_cpu_fan_speeds[] = -{ - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2b, 0x2d, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f -}; - -static unsigned char u450_default_ps_temp_factors[] = -{ - 0x9a, 0x96, 0x82, 0x7d, 0x78, 0x73, 0x6e, 0x6b, - 0x69, 0x67, 0x64, 0x5f, 0x5a, 0x57, 0x55, 0x53, - 0x51, 0x50, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x47, - 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, - 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x39, - 0x38, 0x37, 0x37, 0x36, 0x35, 0x35, 0x34, 0x33, - 0x32, 0x32, 0x32, 0x31, 0x31, 0x30, 0x30, 0x2f, - 0x2f, 0x2e, 0x2e, 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, - 0x2a, 0x2a, 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, - 0x26, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, - 0x23, 0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, - 0x21, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, - 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, 0x1c, - 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, 0x19, 0x19, - 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, - 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, - 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, - 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; +static struct file_operations envctrl_fops = { + owner: THIS_MODULE, + read: envctrl_read, + ioctl: envctrl_ioctl, + open: envctrl_open, + release: envctrl_release, +}; -static unsigned char u450_default_ps_fan_speeds[] = -{ - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x2b, 0x2d, 0x2e, 0x2f, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f +static struct miscdevice envctrl_dev = { + ENVCTRL_MINOR, + "envctrl", + &envctrl_fops }; -static void -u450_toggle_i2c_int(struct environment *env) +/* Function Description: Set monitor type based on firmware description. + * Return: None. + */ +static void envctrl_set_mon(struct i2c_child_t *pchild, + char *chnl_desc, + int chnl_no) +{ + /* Firmware only has temperature type. It does not distinguish + * different kinds of temperatures. We use channel description + * to disinguish them. + */ + if (!(strcmp(chnl_desc,"temp,cpu")) || + !(strcmp(chnl_desc,"temp,cpu0")) || + !(strcmp(chnl_desc,"temp,cpu1")) || + !(strcmp(chnl_desc,"temp,cpu2")) || + !(strcmp(chnl_desc,"temp,cpu3"))) + pchild->mon_type[chnl_no] = ENVCTRL_CPUTEMP_MON; + + if (!(strcmp(chnl_desc,"vddcore,cpu0")) || + !(strcmp(chnl_desc,"vddcore,cpu1")) || + !(strcmp(chnl_desc,"vddcore,cpu2")) || + !(strcmp(chnl_desc,"vddcore,cpu3"))) + pchild->mon_type[chnl_no] = ENVCTRL_CPUVOLTAGE_MON; + + if (!(strcmp(chnl_desc,"temp,motherboard"))) + pchild->mon_type[chnl_no] = ENVCTRL_MTHRBDTEMP_MON; + + if (!(strcmp(chnl_desc,"temp,scsi"))) + pchild->mon_type[chnl_no] = ENVCTRL_SCSITEMP_MON; + + if (!(strcmp(chnl_desc,"temp,ethernet"))) + pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; + + if (!(strcmp(chnl_desc,"temp,ethernet"))) + pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; +} + +/* Function Description: Initialize monitor channel with channel desc, + * decoding tables, monitor type, optional properties. + * Return: None. + */ +static void envctrl_init_adc(struct i2c_child_t *pchild, int node) +{ + char chnls_desc[CHANNEL_DESC_SZ]; + int i, len, j = 0; + char *ptr; + + /* Firmware describe channels into a stream separated by a '\0'. + * Replace all '\0' with a space. + */ + len = prom_getproperty(node, "channels-description", chnls_desc, + CHANNEL_DESC_SZ); + for (i = 0; i < len; i++) { + if (chnls_desc[i] == '\0') + chnls_desc[i] = ' '; + } + + ptr = strtok(chnls_desc, " "); + while (ptr != NULL) { + envctrl_set_mon(pchild, ptr, j); + ptr = strtok(NULL, " "); + j++; + } + + /* Get optional properties. */ + len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature, + sizeof(warning_temperature)); + len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature, + sizeof(shutdown_temperature)); +} + +/* Function Description: Initialize child device monitoring fan status. + * Return: None. + */ +static void envctrl_init_fanstat(struct i2c_child_t *pchild) { - unsigned char tmp[80]; - unsigned char data; - int i, n; + int i; - write_8583(U450_TIMER_ADDR, 0, 0x84); - write_8583(U450_TIMER_ADDR, 8, 0x0a); - write_8583(U450_TIMER_ADDR, 7, 0x00); - write_8583(U450_TIMER_ADDR, 0, 0x04); + /* Go through all channels and set up the mask. */ + for (i = 0; i < pchild->total_chnls; i++) + pchild->fan_mask |= chnls_mask[(pchild->chnl_array[i]).chnl_no]; - n = sprintf(tmp, "envctrl: PCF8583:"); - for (i = 0; i < 16; i++) { - if (read_8583(U450_TIMER_ADDR, i, &data) < 0) { - printk("envctrl: error reading PCF8583\n"); - break; - } - n += sprintf(tmp+n, " %02x", data); - } - printk("%s\n", tmp); - -#if 1 - data = 0x70; - if (i2c_write(U450_PIO_ADDR, &data, 1, 0) != 1) - return; - mdelay(1); - - data = 0x78; - if (i2c_write(U450_PIO_ADDR, &data, 1, 0) != 1) - return; - mdelay(1); -#endif + /* We only need to know if this child has fan status monitored. + * We dont care which channels since we have the mask already. + */ + pchild->mon_type[0] = ENVCTRL_FANSTAT_MON; } -static void -u450_set_egg_timer(struct environment *env) +/* Initialize child device monitoring voltage status. */ +static void envctrl_init_voltage_status(struct i2c_child_t *pchild) { - unsigned char value; - -#if 0 - write_8583(U450_TIMER_ADDR, 0x00, 0x84); - read_8583(U450_TIMER_ADDR, 0x07, &value); - write_8583(U450_TIMER_ADDR, 0x07, 0x00); - write_8583(U450_TIMER_ADDR, 0x00, 0x04); -#else - read_8583(U450_TIMER_ADDR, 0x07, &value); - printk("envctrl: TIMER [%02x:07]: %02x\n", U450_TIMER_ADDR, value); - read_8583(U450_TIMER_ADDR, 0x00, &value); - printk("envctrl: TIMER [%02x:00]: %02x\n", U450_TIMER_ADDR, value); -#endif -} + int i; -static int -envctrl_setup(int node) -{ - struct thermistor *t, **tlast; - struct fan *f, **flast; - unsigned char *tmp = NULL, *p; - int len, n, err; - int defaults = 0; - - len = prom_getproplen(node, "thermisters"); - if (len <= 0) { - printk("envctrl: no property `thermisters', using defaults\n"); - defaults++; - len = sizeof(u450_default_thermisters); - } + /* Go through all channels and set up the mask. */ + for (i = 0; i < pchild->total_chnls; i++) + pchild->voltage_mask |= chnls_mask[(pchild->chnl_array[i]).chnl_no]; - tmp = (unsigned char *)kmalloc(len, GFP_KERNEL); - if (!tmp) { - printk("envctrl: can't allocate property buffer\n"); - return -ENODEV; - } + /* We only need to know if this child has voltage status monitored. + * We dont care which channels since we have the mask already. + */ + pchild->mon_type[0] = ENVCTRL_VOLTAGESTAT_MON; +} - if (defaults) { - memcpy(tmp, u450_default_thermisters, len); - } else { - err = prom_getproperty(node, "thermisters", tmp, len); - if (err < 0) { - printk("envctrl: error reading property `thermisters'\n"); - kfree(tmp); - return -ENODEV; +/* Function Description: Initialize i2c child device. + * Return: None. + */ +static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, + struct i2c_child_t *pchild) +{ + int node, len, i, tbls_size = 0; + + node = edev_child->prom_node; + + /* Get device address. */ + len = prom_getproperty(node, "reg", + (char *) &(pchild->addr), + sizeof(pchild->addr)); + + /* Get tables property. Read firmware temperature tables. */ + len = prom_getproperty(node, "translation", + (char *) pchild->tblprop_array, + (PCF8584_MAX_CHANNELS * + sizeof(struct pcf8584_tblprop))); + if (len > 0) { + pchild->total_tbls = len / sizeof(struct pcf8584_tblprop); + for (i = 0; i < pchild->total_tbls; i++) { + if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) { + tbls_size = pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset; + } } - } - - p = tmp; - err = -ENOMEM; - tlast = &envctrl.thermistors; - while (len > sizeof(struct therm_regs)) { - t = kmalloc(sizeof(struct thermistor), GFP_KERNEL); - if (!t) { - printk("envctrl: can't allocate thermistor struct\n"); - goto out; - } - memset(t, 0, sizeof(struct thermistor)); - - memcpy(&t->regs, p, sizeof(struct therm_regs)); - p += sizeof(struct therm_regs); - len -= sizeof(struct therm_regs); - - n = strlen(p) + 1; - strncpy(t->name, p, 7); - p += n; - len -= n; - - if (!i2c_find_device(t->regs.addr)) { - printk("envctrl: `%s': i2c device %02x not found\n", - t->name, t->regs.addr); - kfree(t); - continue; + pchild->tables = kmalloc(tbls_size, GFP_KERNEL); + len = prom_getproperty(node, "tables", + (char *) pchild->tables, tbls_size); + if (len <= 0) { + printk("envctrl: Failed to get table.\n"); + return; } + } - t->temperature = envctrl_get_temperature; - t->fan_speed = envctrl_get_fan_speed; + /* Get the monitor channels. */ + len = prom_getproperty(node, "channels-in-use", + (char *) pchild->chnl_array, + (PCF8584_MAX_CHANNELS * + sizeof(struct pcf8584_channel))); + pchild->total_chnls = len / sizeof(struct pcf8584_channel); - *tlast = t; - tlast = &t->next; - } + for (i = 0; i < pchild->total_chnls; i++) { + switch (pchild->chnl_array[i].type) { + case PCF8584_TEMP_TYPE: + envctrl_init_adc(pchild, node); + break; - flast = &envctrl.fans; - for (n = 0; n < 2; n++) { - f = kmalloc(sizeof(struct fan), GFP_KERNEL); - if (!f) - goto out; - memset(f, 0, sizeof(struct fan)); - - f->regs.addr = U450_FAN_ADDR; - f->regs.port = n; - - switch (n) { - case U450_FAN_PORT_CPU: - sprintf(f->name, "%.7s", "CPU"); - t = NULL; - while ((t = find_thermistor("CPU", t))) { - t->chain = f->monitor; - f->monitor = t; - } + case PCF8584_FANSTAT_TYPE: + envctrl_init_fanstat(pchild); + i = pchild->total_chnls; break; - case U450_FAN_PORT_PS: - sprintf(f->name, "%.7s", "PS"); - t = NULL; - while ((t = find_thermistor("PS", t))) { - t->chain = f->monitor; - f->monitor = t; + + case PCF8584_VOLTAGE_TYPE: + if (pchild->i2ctype == I2C_ADC) { + envctrl_init_adc(pchild,node); + } else { + envctrl_init_voltage_status(pchild); } + i = pchild->total_chnls; break; - } - - if (!f->monitor) { - kfree(f); - continue; - } - - if (!i2c_find_device(f->regs.addr)) { - printk("envctrl: `%s': i2c device %02x not found\n", - f->name, f->regs.addr); - kfree(f); - continue; - } - - *flast = f; - flast = &f->next; - f->check_failure = NULL; - f->set_speed = envctrl_set_fan_speed; - } - - envctrl.cpu_temp_table = kmalloc(256, GFP_KERNEL); - if (!envctrl.cpu_temp_table) { - printk("envctrl: can't allocate temperature table\n"); - goto out; - } - if (defaults) { - memcpy(envctrl.cpu_temp_table, - u450_default_cpu_temp_factors, 256); - } else { - err = prom_getproperty(node, "cpu-temp-factors", - envctrl.cpu_temp_table, 256); - if (err < 0) { - printk("envctrl: can't read `cpu-temp-factors'\n"); - goto out; - } - } - - envctrl.cpu_fan_speeds = kmalloc(112, GFP_KERNEL); - if (!envctrl.cpu_fan_speeds) { - printk("envctrl: can't allocate fan speed table\n"); - goto out; - } - if (defaults) { - memcpy(envctrl.cpu_fan_speeds, - u450_default_cpu_fan_speeds, 112); - } else { - err = prom_getproperty(node, "cpu-fan-speeds", - envctrl.cpu_fan_speeds, 112); - if (err < 0) { - printk("envctrl: can't read `cpu-fan-speeds'\n"); - goto out; - } - } - - envctrl.ps_temp_table = kmalloc(256, GFP_KERNEL); - if (!envctrl.ps_temp_table) { - printk("envctrl: can't allocate temperature table\n"); - goto out; - } - if (defaults) { - memcpy(envctrl.ps_temp_table, - u450_default_ps_temp_factors, 256); - } else { - err = prom_getproperty(node, "ps-temp-factors", - envctrl.ps_temp_table, 256); - if (err < 0) { - printk("envctrl: can't read `ps-temp-factors'\n"); - goto out; - } - } - - envctrl.ps_fan_speeds = kmalloc(112, GFP_KERNEL); - if (!envctrl.ps_fan_speeds) { - printk("envctrl: can't allocate fan speed table\n"); - goto out; - } - if (defaults) { - memcpy(envctrl.ps_fan_speeds, - u450_default_ps_fan_speeds, 112); - } else { - err = prom_getproperty(node, "ps-fan-speeds", - envctrl.ps_fan_speeds, 112); - if (err < 0) { - printk("envctrl: can't read `ps-fan-speeds'\n"); - goto out; - } + default: + break; + }; } - - envctrl.enable = u450_toggle_i2c_int; - envctrl.keep_alive = u450_set_egg_timer; - envctrl.disable = envctrl_fans_blast; - envctrl.interval = 60; - - kfree(tmp); - return 0; - -out: - if (tmp) - kfree(tmp); - return err; -} -#endif /* U450_SUPPORT */ - - - -static loff_t -envctrl_llseek(struct file *file, loff_t offset, int type) -{ - return -ESPIPE; -} - -static ssize_t -envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - unsigned long addr = (unsigned long)file->private_data; - - return i2c_read(addr, buf, count, 1); -} - -static ssize_t -envctrl_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - unsigned long addr = (unsigned long)file->private_data; - - return i2c_write(addr, buf, count, 1); } -static int -envctrl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +/* Function Description: Search the child device list for a device. + * Return : The i2c child if found. NULL otherwise. + */ +static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type) { - unsigned long data; - int addr; + int i, j; - switch (cmd) { - case I2CIOCSADR: - if (get_user(addr, (int *)arg)) - return -EFAULT; - data = addr & 0xfe; - if (!i2c_find_device(addr & 0xfe)) - return -ENODEV; - file->private_data = (void *)data; - break; - case I2CIOCGADR: - addr = (unsigned long)file->private_data; - if (put_user(addr, (int *)arg)) - return -EFAULT; - break; - default: - return -EINVAL; + for (i = 0; i < ENVCTRL_MAX_CPU*2; i++) { + for (j = 0; j < PCF8584_MAX_CHANNELS; j++) { + if (i2c_childlist[i].mon_type[j] == mon_type) { + return (struct i2c_child_t*)(&(i2c_childlist[i])); + } + } } - return 0; + return NULL; } -static int -envctrl_open(struct inode *inode, struct file *file) -{ - file->private_data = 0; - return 0; -} - -static struct file_operations envctrl_fops = { - owner: THIS_MODULE, - llseek: envctrl_llseek, - read: envctrl_read, - write: envctrl_write, - ioctl: envctrl_ioctl, - open: envctrl_open, -}; - -static struct miscdevice envctrl_dev = { - ENVCTRL_MINOR, - "envctrl", - &envctrl_fops -}; - -#ifdef MODULE -int init_module(void) -#else -int __init envctrl_init(void) -#endif +static int __init envctrl_init(void) { #ifdef CONFIG_PCI - struct linux_ebus *ebus; - struct linux_ebus_device *edev = 0; - pid_t pid; - int err; - + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + struct linux_ebus_child *edev_child = NULL; + int i = 0; + + /* Traverse through ebus and ebus device list for i2c device and + * adc and gpio nodes. + */ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "SUNW,envctrl")) - goto ebus_done; - if (!strcmp(edev->prom_name, "SUNW,rasctrl")) - goto ebus_done; + if (!strcmp(edev->prom_name, "i2c")) { + i2c = ioremap( edev->resource[0].start, + sizeof(struct pcf8584_reg)); + for_each_edevchild(edev, edev_child) { + if (!strcmp("gpio", edev_child->prom_name)) { + i2c_childlist[i].i2ctype = I2C_GPIO; + envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); + } + if (!strcmp("adc", edev_child->prom_name)) { + i2c_childlist[i].i2ctype = I2C_ADC; + envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); + } + } + goto done; + } } } -ebus_done: - if (!edev) { - printk("%s: ebus device not found\n", __FUNCTION__); - return -ENODEV; - } - - i2c_regs = (unsigned long) ioremap(edev->resource[0].start, I2C_REG_SIZE); - writeb(CONTROL_PIN, i2c_regs + I2C_CSR); - writeb(PCF8584_ADDRESS >> 1, i2c_regs + I2C_DATA); - writeb(CONTROL_PIN | CONTROL_ES1, i2c_regs + I2C_CSR); - writeb(CLK_4_43 | BUS_CLK_90, i2c_regs + I2C_DATA); - writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, i2c_regs + I2C_CSR); - mdelay(10); - if (misc_register(&envctrl_dev)) { - printk("%s: unable to get misc minor %d\n", - __FUNCTION__, envctrl_dev.minor); +done: + if (!edev) { + printk("envctrl: I2C device not found.\n"); return -ENODEV; } - err = i2c_scan_bus(); - if (err) { - i2c_free_devices(); - misc_deregister(&envctrl_dev); - return err; - } + /* Set device address. */ + envctrl_writeb(CONTROL_PIN, &i2c->csr); + envctrl_writeb(PCF8584_ADDRESS, &i2c->data); - memset(&envctrl, 0, sizeof(struct environment)); + /* Set system clock and SCL frequencies. */ + envctrl_writeb(CONTROL_PIN | CONTROL_ES1, &i2c->csr); + envctrl_writeb(CLK_4_43 | BUS_CLK_90, &i2c->data); - err = -ENODEV; - if (!strcmp(edev->prom_name, "SUNW,rasctrl")) - err = rasctrl_setup(edev->prom_node); -#ifdef U450_SUPPORT - else if (!strcmp(edev->prom_name, "SUNW,envctrl")) - err = envctrl_setup(edev->prom_node); -#endif + /* Enable serial interface. */ + envctrl_writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, &i2c->csr); + udelay(200); - if (err) { - envctrl_stop(); - i2c_free_devices(); - misc_deregister(&envctrl_dev); - return err; + /* Register the device as a minor miscellaneous device. */ + if (misc_register(&envctrl_dev)) { + printk("envctrl: Unable to get misc minor %d\n", + envctrl_dev.minor); } - init_waitqueue_head(&envctrl.kenvd_wait); - - pid = kernel_thread(kenvd, (void *)&envctrl, CLONE_FS); - if (pid < 0) { - envctrl_stop(); - i2c_free_devices(); - misc_deregister(&envctrl_dev); - return -ENODEV; + /* Note above traversal routine post-incremented 'i' to accomodate + * a next child device, so we decrement before reverse-traversal of + * child devices. + */ + printk("envctrl: initialized "); + for(--i; i >= 0; --i) + { + printk("[%s 0x%lx]%s", + (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : + ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), + i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); } return 0; @@ -1605,13 +946,18 @@ ebus_done: #endif } - -#ifdef MODULE -void cleanup_module(void) +static void __exit envctrl_cleanup(void) { - envctrl_stop(); - i2c_free_devices(); - iounmap(i2c_regs); + int i; + + iounmap(i2c); misc_deregister(&envctrl_dev); + + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { + if (i2c_childlist[i].tables) + kfree(i2c_childlist[i].tables); + } } -#endif + +module_init(envctrl_init); +module_exit(envctrl_cleanup); diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 7d010f035..ae7ba7ac1 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.51 2000/09/04 19:41:26 ecd Exp $ +/* $Id: sab82532.c,v 1.52 2000/10/14 10:09:04 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2133,7 +2133,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.51 $"; + char *revision = "$Revision: 1.52 $"; char *version, *p; version = strchr(revision, ' '); @@ -2596,17 +2596,13 @@ sab82532_console_setup(struct console *con, char *options) } static struct console sab82532_console = { - "ttyS", - sab82532_console_write, - NULL, - sab82532_console_device, - sab82532_console_wait_key, - NULL, - sab82532_console_setup, - CON_PRINTBUFFER, - -1, - 0, - NULL + name: "ttyS", + write: sab82532_console_write, + device: sab82532_console_device, + wait_key: sab82532_console_wait_key, + setup: sab82532_console_setup, + flags: CON_PRINTBUFFER, + index: -1, }; int __init sab82532_console_init(void) diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index c6e90328e..1fd2d6fbf 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.41 2000/09/04 19:41:27 ecd Exp $ +/* $Id: su.c,v 1.42 2000/10/14 10:09:04 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2219,7 +2219,7 @@ done: */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.41 $"; + char *revision = "$Revision: 1.42 $"; char *version, *p; version = strchr(revision, ' '); @@ -2938,17 +2938,13 @@ static int __init serial_console_setup(struct console *co, char *options) } static struct console sercons = { - "ttyS", - serial_console_write, - NULL, - serial_console_device, - serial_console_wait_key, - NULL, - serial_console_setup, - CON_PRINTBUFFER, - -1, - 0, - NULL + name: "ttyS", + write: serial_console_write, + device: serial_console_device, + wait_key: serial_console_wait_key, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, }; int su_console_registered = 0; diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 5540e734b..f34c12250 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -80,7 +80,7 @@ extern void reset_vc(unsigned int new_console); extern void scrollback(int); extern void scrollfront(int); -struct l1a_kbd_state l1a_state = { 0, 0 }; +struct l1a_kbd_state l1a_state; #ifndef CONFIG_PCI DECLARE_WAIT_QUEUE_HEAD(keypress_wait); @@ -101,30 +101,30 @@ static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED; */ /* shift state counters.. */ -static unsigned char k_down[NR_SHIFT] = {0, }; +static unsigned char k_down[NR_SHIFT]; /* keyboard key bitmap */ -static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; +static unsigned long key_down[256/BITS_PER_LONG]; void push_kbd (int scan); -int kbd_redirected = 0; +int kbd_redirected; -static int dead_key_next = 0; +static int dead_key_next; /* * In order to retrieve the shift_state (for the mouse server), either * the variable must be global, or a new procedure must be created to * return the value. I chose the former way. */ #ifndef CONFIG_PCI -/*static*/ int shift_state = 0; +/*static*/ int shift_state; #endif static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr = 0; -static char rep = 0; /* flag telling character repeat */ +static unsigned char diacr; +static char rep; /* flag telling character repeat */ struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct tty_struct **ttytab; static struct kbd_struct * kbd = kbd_table; -static struct tty_struct * tty = NULL; -static int compose_led_on = 0; +static struct tty_struct * tty; +static int compose_led_on; static int kbd_delay_ticks = HZ / 5; static int kbd_rate_ticks = HZ / 20; diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 77b849ef0..73158f351 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -43,7 +43,7 @@ #include <asm/vfc_ioctls.h> static struct file_operations vfc_fops; -static devfs_handle_t devfs_handle = NULL; /* For the directory */ +static devfs_handle_t devfs_handle; /* For the directory */ struct vfc_dev **vfc_dev_lst; static char vfcstr[]="vfc"; static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 7acfb2aba..67ef24fd3 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.59 2000/08/29 07:01:55 davem Exp $ +/* $Id: zs.c,v 1.60 2000/10/14 10:09:04 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1913,7 +1913,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.59 $"; + char *revision = "$Revision: 1.60 $"; char *version, *p; version = strchr(revision, ' '); @@ -2830,17 +2830,13 @@ static int __init zs_console_setup(struct console *con, char *options) } static struct console zs_console = { - "ttyS", - zs_console_write, - NULL, - zs_console_device, - zs_console_wait_key, - NULL, - zs_console_setup, - CON_PRINTBUFFER, - -1, - 0, - NULL + name: "ttyS", + write: zs_console_write, + device: zs_console_device, + wait_key: zs_console_wait_key, + setup: zs_console_setup, + flags: CON_PRINTBUFFER, + index: -1, }; static int __init zs_console_init(void) |