aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/amiserial.c22
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/ds1620.c3
-rw-r--r--drivers/char/ftape/compressor/zftape-compress.c4
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/i8k.c909
-rw-r--r--drivers/char/ip2/i2cmd.c6
-rw-r--r--drivers/char/ip2/i2cmd.h12
-rw-r--r--drivers/char/ip2main.c10
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c196
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c46
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c137
-rw-r--r--drivers/char/isicom.c12
-rw-r--r--drivers/char/istallion.c3
-rw-r--r--drivers/char/mem.c53
-rw-r--r--drivers/char/misc.c8
-rw-r--r--drivers/char/mwave/3780i.c6
-rw-r--r--drivers/char/mwave/3780i.h4
-rw-r--r--drivers/char/mwave/tp3780i.c14
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/n_r3964.c2
-rw-r--r--drivers/char/nvram.c6
-rw-r--r--drivers/char/rio/func.h1
-rw-r--r--drivers/char/rio/rio_linux.c5
-rw-r--r--drivers/char/rio/rioinit.c7
-rw-r--r--drivers/char/rio/riotty.c15
-rw-r--r--drivers/char/rocket.c226
-rw-r--r--drivers/char/rocket_int.h40
-rw-r--r--drivers/char/sysrq.c24
-rw-r--r--drivers/char/toshiba.c60
-rw-r--r--drivers/char/tpm/tpm.c360
-rw-r--r--drivers/char/tpm/tpm.h38
-rw-r--r--drivers/char/tpm/tpm_atmel.c63
-rw-r--r--drivers/char/tpm/tpm_nsc.c199
-rw-r--r--drivers/char/tty_io.c47
-rw-r--r--drivers/char/watchdog/Kconfig10
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/wdrtas.c696
39 files changed, 1984 insertions, 1271 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7ccf871d3c9..43d0cb19ef6 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -940,8 +940,8 @@ config RAW_DRIVER
Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
See the raw(8) manpage for more details.
- The raw driver is deprecated and may be removed from 2.7
- kernels. Applications should simply open the device (eg /dev/hda1)
+ The raw driver is deprecated and will be removed soon.
+ Applications should simply open the device (eg /dev/hda1)
with the O_DIRECT flag.
config HPET
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 1dc4259213a..2a36561eec6 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -861,13 +861,18 @@ static void change_speed(struct async_struct *info,
static void rs_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
+ struct async_struct *info;
unsigned long flags;
+ if (!tty)
+ return;
+
+ info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
return;
- if (!tty || !info->xmit.buf)
+ if (!info->xmit.buf)
return;
local_irq_save(flags);
@@ -910,13 +915,18 @@ static void rs_flush_chars(struct tty_struct *tty)
static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
{
int c, ret = 0;
- struct async_struct *info = (struct async_struct *)tty->driver_data;
+ struct async_struct *info;
unsigned long flags;
+ if (!tty)
+ return 0;
+
+ info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!tty || !info->xmit.buf || !tmp_buf)
+ if (!info->xmit.buf || !tmp_buf)
return 0;
local_save_flags(flags);
@@ -1963,10 +1973,6 @@ static _INLINE_ void show_serial_version(void)
}
-int register_serial(struct serial_struct *req);
-void unregister_serial(int line);
-
-
static struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 6bf2e27dc23..11f9ee58112 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -599,7 +599,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_
#ifdef DEBUG
if (loopcount++ > 2) {
- printk("Looping in ac_read. loopcount %d\n", loopcount);
+ printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount);
}
#endif
}
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 7def6ad5179..62cda25724e 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -163,8 +163,7 @@ static void ds1620_out(int cmd, int bits, int value)
netwinder_ds1620_reset();
netwinder_unlock(&flags);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2);
+ msleep(20);
}
static unsigned int ds1620_in(int cmd, int bits)
diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c
index 220a227e606..65ffc0be3df 100644
--- a/drivers/char/ftape/compressor/zftape-compress.c
+++ b/drivers/char/ftape/compressor/zftape-compress.c
@@ -1176,8 +1176,8 @@ KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n");
}
#else /* !MODULE */
/* print a short no-nonsense boot message */
- printk("zftape compressor v1.00a 970514\n");
- printk("For use with " FTAPE_VERSION "\n");
+ printk(KERN_INFO "zftape compressor v1.00a 970514\n");
+ printk(KERN_INFO "For use with " FTAPE_VERSION "\n");
#endif /* MODULE */
TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init);
TRACE(ft_t_info, "installing compressor for zftape ...");
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 5ec732e6ca9..762fa430fb5 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp)
printk("\n");
ns = hpetp->hp_period; /* femptoseconds, 10^-15 */
- do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */
+ ns /= 1000000; /* convert to nanoseconds, 10^-9 */
printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n",
hpetp->hp_which, ns, hpetp->hp_ntimer,
cap & HPET_COUNTER_SIZE_MASK ? 64 : 32);
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index a8119764028..6c4b3f986d0 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -20,13 +20,14 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <linux/apm_bios.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/i8k.h>
-#define I8K_VERSION "1.13 14/05/2002"
+#define I8K_VERSION "1.14 21/02/2005"
#define I8K_SMM_FN_STATUS 0x0025
#define I8K_SMM_POWER_STATUS 0x0069
@@ -34,7 +35,8 @@
#define I8K_SMM_GET_FAN 0x00a3
#define I8K_SMM_GET_SPEED 0x02a3
#define I8K_SMM_GET_TEMP 0x10a3
-#define I8K_SMM_GET_DELL_SIG 0xffa3
+#define I8K_SMM_GET_DELL_SIG1 0xfea3
+#define I8K_SMM_GET_DELL_SIG2 0xffa3
#define I8K_SMM_BIOS_VERSION 0x00a6
#define I8K_FAN_MULT 30
@@ -52,18 +54,7 @@
#define I8K_TEMPERATURE_BUG 1
-#define DELL_SIGNATURE "Dell Computer"
-
-static char *supported_models[] = {
- "Inspiron",
- "Latitude",
- NULL
-};
-
-static char system_vendor[48] = "?";
-static char product_name [48] = "?";
-static char bios_version [4] = "?";
-static char serial_number[16] = "?";
+static char bios_version[4];
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -73,6 +64,10 @@ static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+static int ignore_dmi;
+module_param(ignore_dmi, bool, 0);
+MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
+
static int restricted;
module_param(restricted, bool, 0);
MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
@@ -81,69 +76,69 @@ static int power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
-static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *);
+static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static struct file_operations i8k_fops = {
- .read = i8k_read,
- .ioctl = i8k_ioctl,
+ .open = i8k_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .ioctl = i8k_ioctl,
+};
+
+struct smm_regs {
+ unsigned int eax;
+ unsigned int ebx __attribute__ ((packed));
+ unsigned int ecx __attribute__ ((packed));
+ unsigned int edx __attribute__ ((packed));
+ unsigned int esi __attribute__ ((packed));
+ unsigned int edi __attribute__ ((packed));
};
-typedef struct {
- unsigned int eax;
- unsigned int ebx __attribute__ ((packed));
- unsigned int ecx __attribute__ ((packed));
- unsigned int edx __attribute__ ((packed));
- unsigned int esi __attribute__ ((packed));
- unsigned int edi __attribute__ ((packed));
-} SMMRegisters;
-
-typedef struct {
- u8 type;
- u8 length;
- u16 handle;
-} DMIHeader;
+static inline char *i8k_get_dmi_data(int field)
+{
+ return dmi_get_system_info(field) ? : "N/A";
+}
/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
*/
-static int i8k_smm(SMMRegisters *regs)
+static int i8k_smm(struct smm_regs *regs)
{
- int rc;
- int eax = regs->eax;
-
- asm("pushl %%eax\n\t" \
- "movl 0(%%eax),%%edx\n\t" \
- "push %%edx\n\t" \
- "movl 4(%%eax),%%ebx\n\t" \
- "movl 8(%%eax),%%ecx\n\t" \
- "movl 12(%%eax),%%edx\n\t" \
- "movl 16(%%eax),%%esi\n\t" \
- "movl 20(%%eax),%%edi\n\t" \
- "popl %%eax\n\t" \
- "out %%al,$0xb2\n\t" \
- "out %%al,$0x84\n\t" \
- "xchgl %%eax,(%%esp)\n\t"
- "movl %%ebx,4(%%eax)\n\t" \
- "movl %%ecx,8(%%eax)\n\t" \
- "movl %%edx,12(%%eax)\n\t" \
- "movl %%esi,16(%%eax)\n\t" \
- "movl %%edi,20(%%eax)\n\t" \
- "popl %%edx\n\t" \
- "movl %%edx,0(%%eax)\n\t" \
- "lahf\n\t" \
- "shrl $8,%%eax\n\t" \
- "andl $1,%%eax\n" \
- : "=a" (rc)
- : "a" (regs)
- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-
- if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
- return -EINVAL;
- }
-
- return 0;
+ int rc;
+ int eax = regs->eax;
+
+ asm("pushl %%eax\n\t"
+ "movl 0(%%eax),%%edx\n\t"
+ "push %%edx\n\t"
+ "movl 4(%%eax),%%ebx\n\t"
+ "movl 8(%%eax),%%ecx\n\t"
+ "movl 12(%%eax),%%edx\n\t"
+ "movl 16(%%eax),%%esi\n\t"
+ "movl 20(%%eax),%%edi\n\t"
+ "popl %%eax\n\t"
+ "out %%al,$0xb2\n\t"
+ "out %%al,$0x84\n\t"
+ "xchgl %%eax,(%%esp)\n\t"
+ "movl %%ebx,4(%%eax)\n\t"
+ "movl %%ecx,8(%%eax)\n\t"
+ "movl %%edx,12(%%eax)\n\t"
+ "movl %%esi,16(%%eax)\n\t"
+ "movl %%edi,20(%%eax)\n\t"
+ "popl %%edx\n\t"
+ "movl %%edx,0(%%eax)\n\t"
+ "lahf\n\t"
+ "shrl $8,%%eax\n\t"
+ "andl $1,%%eax\n":"=a"(rc)
+ : "a"(regs)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+
+ if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
+ return -EINVAL;
+
+ return 0;
}
/*
@@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs)
*/
static int i8k_get_bios_version(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_BIOS_VERSION;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return regs.eax;
-}
+ struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };
-/*
- * Read the machine id.
- */
-static int i8k_get_serial_number(unsigned char *buff)
-{
- strlcpy(buff, serial_number, sizeof(serial_number));
- return 0;
+ return i8k_smm(&regs) ? : regs.eax;
}
/*
@@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff)
*/
static int i8k_get_fn_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_FN_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
- case I8K_FN_UP:
- return I8K_VOL_UP;
- case I8K_FN_DOWN:
- return I8K_VOL_DOWN;
- case I8K_FN_MUTE:
- return I8K_VOL_MUTE;
- default:
- return 0;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
+ int rc;
+
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
+
+ switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
+ case I8K_FN_UP:
+ return I8K_VOL_UP;
+ case I8K_FN_DOWN:
+ return I8K_VOL_DOWN;
+ case I8K_FN_MUTE:
+ return I8K_VOL_MUTE;
+ default:
+ return 0;
+ }
}
/*
@@ -202,20 +180,13 @@ static int i8k_get_fn_status(void)
*/
static int i8k_get_power_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_POWER_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch (regs.eax & 0xff) {
- case I8K_POWER_AC:
- return I8K_AC;
- default:
- return I8K_BATTERY;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
+ int rc;
+
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
+
+ return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
}
/*
@@ -223,16 +194,10 @@ static int i8k_get_power_status(void)
*/
static int i8k_get_fan_status(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_GET_FAN;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
- return (regs.eax & 0xff);
+ regs.ebx = fan & 0xff;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
}
/*
@@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan)
*/
static int i8k_get_fan_speed(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
- regs.eax = I8K_SMM_GET_SPEED;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return (regs.eax & 0xffff) * I8K_FAN_MULT;
+ regs.ebx = fan & 0xff;
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
}
/*
@@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan)
*/
static int i8k_set_fan(int fan, int speed)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+ struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
- regs.eax = I8K_SMM_SET_FAN;
- regs.ebx = (fan & 0xff) | (speed << 8);
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+ regs.ebx = (fan & 0xff) | (speed << 8);
- return (i8k_get_fan_status(fan));
+ return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
}
/*
* Read the cpu temperature.
*/
-static int i8k_get_cpu_temp(void)
+static int i8k_get_temp(int sensor)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
- int temp;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
+ int rc;
+ int temp;
#ifdef I8K_TEMPERATURE_BUG
- static int prev = 0;
+ static int prev;
#endif
+ regs.ebx = sensor & 0xff;
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
- regs.eax = I8K_SMM_GET_TEMP;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
- temp = regs.eax & 0xff;
+ temp = regs.eax & 0xff;
#ifdef I8K_TEMPERATURE_BUG
- /*
- * Sometimes the temperature sensor returns 0x99, which is out of range.
- * In this case we return (once) the previous cached value. For example:
- # 1003655137 00000058 00005a4b
- # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
- # 1003655139 00000054 00005c52
- */
- if (temp > I8K_MAX_TEMP) {
- temp = prev;
- prev = I8K_MAX_TEMP;
- } else {
- prev = temp;
- }
+ /*
+ * Sometimes the temperature sensor returns 0x99, which is out of range.
+ * In this case we return (once) the previous cached value. For example:
+ # 1003655137 00000058 00005a4b
+ # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
+ # 1003655139 00000054 00005c52
+ */
+ if (temp > I8K_MAX_TEMP) {
+ temp = prev;
+ prev = I8K_MAX_TEMP;
+ } else {
+ prev = temp;
+ }
#endif
- return temp;
+ return temp;
}
-static int i8k_get_dell_signature(void)
+static int i8k_get_dell_signature(int req_fn)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = req_fn, };
+ int rc;
- regs.eax = I8K_SMM_GET_DELL_SIG;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
- if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
- return 0;
- } else {
- return -1;
- }
+ return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
}
static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
unsigned long arg)
{
- int val;
- int speed;
- unsigned char buff[16];
- int __user *argp = (int __user *)arg;
-
- if (!argp)
- return -EINVAL;
-
- switch (cmd) {
- case I8K_BIOS_VERSION:
- val = i8k_get_bios_version();
- break;
-
- case I8K_MACHINE_ID:
- memset(buff, 0, 16);
- val = i8k_get_serial_number(buff);
- break;
-
- case I8K_FN_STATUS:
- val = i8k_get_fn_status();
- break;
-
- case I8K_POWER_STATUS:
- val = i8k_get_power_status();
- break;
-
- case I8K_GET_TEMP:
- val = i8k_get_cpu_temp();
- break;
-
- case I8K_GET_SPEED:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_speed(val);
- break;
-
- case I8K_GET_FAN:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_status(val);
- break;
+ int val = 0;
+ int speed;
+ unsigned char buff[16];
+ int __user *argp = (int __user *)arg;
- case I8K_SET_FAN:
- if (restricted && !capable(CAP_SYS_ADMIN)) {
- return -EPERM;
- }
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- if (copy_from_user(&speed, argp+1, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_set_fan(val, speed);
- break;
+ if (!argp)
+ return -EINVAL;
- default:
- return -EINVAL;
- }
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ val = i8k_get_bios_version();
+ break;
- if (val < 0) {
- return val;
- }
+ case I8K_MACHINE_ID:
+ memset(buff, 0, 16);
+ strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff));
+ break;
- switch (cmd) {
- case I8K_BIOS_VERSION:
- if (copy_to_user(argp, &val, 4)) {
- return -EFAULT;
- }
- break;
- case I8K_MACHINE_ID:
- if (copy_to_user(argp, buff, 16)) {
- return -EFAULT;
- }
- break;
- default:
- if (copy_to_user(argp, &val, sizeof(int))) {
- return -EFAULT;
- }
- break;
- }
+ case I8K_FN_STATUS:
+ val = i8k_get_fn_status();
+ break;
- return 0;
-}
+ case I8K_POWER_STATUS:
+ val = i8k_get_power_status();
+ break;
-/*
- * Print the information for /proc/i8k.
- */
-static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
-{
- int n, fn_key, cpu_temp, ac_power;
- int left_fan, right_fan, left_speed, right_speed;
-
- cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */
- left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
- right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
- left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
- right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
- fn_key = i8k_get_fn_status(); /* 750 µs */
- if (power_status) {
- ac_power = i8k_get_power_status(); /* 14700 µs */
- } else {
- ac_power = -1;
- }
-
- /*
- * Info:
- *
- * 1) Format version (this will change if format changes)
- * 2) BIOS version
- * 3) BIOS machine ID
- * 4) Cpu temperature
- * 5) Left fan status
- * 6) Right fan status
- * 7) Left fan speed
- * 8) Right fan speed
- * 9) AC power
- * 10) Fn Key status
- */
- n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
- I8K_PROC_FMT,
- bios_version,
- serial_number,
- cpu_temp,
- left_fan,
- right_fan,
- left_speed,
- right_speed,
- ac_power,
- fn_key);
-
- return n;
-}
+ case I8K_GET_TEMP:
+ val = i8k_get_temp(0);
+ break;
-static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos)
-{
- int n;
- char info[128];
+ case I8K_GET_SPEED:
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
- n = i8k_get_info(info, NULL, 0, 128);
- if (n <= 0) {
- return n;
- }
+ val = i8k_get_fan_speed(val);
+ break;
- if (*fpos >= n) {
- return 0;
- }
+ case I8K_GET_FAN:
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
- if ((*fpos + len) >= n) {
- len = n - *fpos;
- }
+ val = i8k_get_fan_status(val);
+ break;
- if (copy_to_user(buffer, info, len) != 0) {
- return -EFAULT;
- }
+ case I8K_SET_FAN:
+ if (restricted && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
- *fpos += len;
- return len;
-}
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
-static char* __init string_trim(char *s, int size)
-{
- int len;
- char *p;
+ if (copy_from_user(&speed, argp + 1, sizeof(int)))
+ return -EFAULT;
- if ((len = strlen(s)) > size) {
- len = size;
- }
+ val = i8k_set_fan(val, speed);
+ break;
- for (p=s+len-1; len && (*p==' '); len--,p--) {
- *p = '\0';
- }
+ default:
+ return -EINVAL;
+ }
- return s;
-}
+ if (val < 0)
+ return val;
-/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ if (copy_to_user(argp, &val, 4))
+ return -EFAULT;
-/*
- * |<-- dmi->length -->|
- * | |
- * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0
- * | |
- * +-----------------------+
- */
-static char* __init dmi_string(DMIHeader *dmi, u8 s)
-{
- u8 *p;
+ break;
+ case I8K_MACHINE_ID:
+ if (copy_to_user(argp, buff, 16))
+ return -EFAULT;
- if (!s) {
- return "";
- }
- s--;
+ break;
+ default:
+ if (copy_to_user(argp, &val, sizeof(int)))
+ return -EFAULT;
- p = (u8 *)dmi + dmi->length;
- while (s > 0) {
- p += strlen(p);
- p++;
- s--;
- }
+ break;
+ }
- return p;
+ return 0;
}
-static void __init dmi_decode(DMIHeader *dmi)
+/*
+ * Print the information for /proc/i8k.
+ */
+static int i8k_proc_show(struct seq_file *seq, void *offset)
{
- u8 *data = (u8 *) dmi;
- char *p;
-
-#ifdef I8K_DEBUG
- int i;
- printk("%08x ", (int)data);
- for (i=0; i<data[1] && i<64; i++) {
- printk("%02x ", data[i]);
- }
- printk("\n");
-#endif
-
- switch (dmi->type) {
- case 0: /* BIOS Information */
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(bios_version, p, sizeof(bios_version));
- string_trim(bios_version, sizeof(bios_version));
- }
- break;
- case 1: /* System Information */
- p = dmi_string(dmi,data[4]);
- if (*p) {
- strlcpy(system_vendor, p, sizeof(system_vendor));
- string_trim(system_vendor, sizeof(system_vendor));
- }
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(product_name, p, sizeof(product_name));
- string_trim(product_name, sizeof(product_name));
- }
- p = dmi_string(dmi,data[7]);
- if (*p) {
- strlcpy(serial_number, p, sizeof(serial_number));
- string_trim(serial_number, sizeof(serial_number));
- }
- break;
- }
-}
+ int fn_key, cpu_temp, ac_power;
+ int left_fan, right_fan, left_speed, right_speed;
+
+ cpu_temp = i8k_get_temp(0); /* 11100 µs */
+ left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
+ right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
+ left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
+ right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
+ fn_key = i8k_get_fn_status(); /* 750 µs */
+ if (power_status)
+ ac_power = i8k_get_power_status(); /* 14700 µs */
+ else
+ ac_power = -1;
-static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
-{
- u8 *buf;
- u8 *data;
- DMIHeader *dmi;
- int i = 1;
-
- buf = ioremap(base, len);
- if (buf == NULL) {
- return -1;
- }
- data = buf;
-
- /*
- * Stop when we see al the items the table claimed to have
- * or we run off the end of the table (also happens)
- */
- while ((i<num) && ((data-buf) < len)) {
- dmi = (DMIHeader *)data;
- /*
- * Avoid misparsing crud if the length of the last
- * record is crap
- */
- if ((data-buf+dmi->length) >= len) {
- break;
- }
- fn(dmi);
- data += dmi->length;
/*
- * Don't go off the end of the data if there is
- * stuff looking like string fill past the end
+ * Info:
+ *
+ * 1) Format version (this will change if format changes)
+ * 2) BIOS version
+ * 3) BIOS machine ID
+ * 4) Cpu temperature
+ * 5) Left fan status
+ * 6) Right fan status
+ * 7) Left fan speed
+ * 8) Right fan speed
+ * 9) AC power
+ * 10) Fn Key status
*/
- while (((data-buf) < len) && (*data || data[1])) {
- data++;
- }
- data += 2;
- i++;
- }
- iounmap(buf);
-
- return 0;
+ return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
+ I8K_PROC_FMT,
+ bios_version,
+ dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
+ cpu_temp,
+ left_fan, right_fan, left_speed, right_speed,
+ ac_power, fn_key);
}
-static int __init dmi_iterate(void (*decode)(DMIHeader *))
+static int i8k_open_fs(struct inode *inode, struct file *file)
{
- unsigned char buf[20];
- void __iomem *p = ioremap(0xe0000, 0x20000), *q;
-
- if (!p)
- return -1;
-
- for (q = p; q < p + 0x20000; q += 16) {
- memcpy_fromio(buf, q, 20);
- if (memcmp(buf, "_DMI_", 5)==0) {
- u16 num = buf[13]<<8 | buf[12];
- u16 len = buf [7]<<8 | buf [6];
- u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
-#ifdef I8K_DEBUG
- printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14]>>4, buf[14]&0x0F);
- printk(KERN_INFO "%d structures occupying %d bytes.\n",
- buf[13]<<8 | buf[12],
- buf [7]<<8 | buf[6]);
- printk(KERN_INFO "DMI table at 0x%08X.\n",
- buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
-#endif
- if (dmi_table(base, len, num, decode)==0) {
- iounmap(p);
- return 0;
- }
- }
- }
- iounmap(p);
- return -1;
+ return single_open(file, i8k_proc_show, NULL);
}
-/* end of DMI code */
-
-/*
- * Get DMI information.
- */
-static int __init i8k_dmi_probe(void)
-{
- char **p;
-
- if (dmi_iterate(dmi_decode) != 0) {
- printk(KERN_INFO "i8k: unable to get DMI information\n");
- return -ENODEV;
- }
-
- if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
- printk(KERN_INFO "i8k: not running on a Dell system\n");
- return -ENODEV;
- }
-
- for (p=supported_models; ; p++) {
- if (!*p) {
- printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
- return -ENODEV;
- }
- if (strncmp(product_name,*p,strlen(*p)) == 0) {
- break;
- }
- }
- return 0;
-}
+static struct dmi_system_id __initdata i8k_dmi_table[] = {
+ {
+ .ident = "Dell Inspiron",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
+ .ident = "Dell Latitude",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+ },
+ },
+ {
+ .ident = "Dell Inspiron 2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
+ .ident = "Dell Latitude 2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+ },
+ },
+ { }
+};
/*
* Probe for the presence of a supported laptop.
*/
static int __init i8k_probe(void)
{
- char buff[4];
- int version;
- int smm_found = 0;
-
- /*
- * Get DMI information
- */
- if (i8k_dmi_probe() != 0) {
- printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
- system_vendor, product_name, bios_version);
- }
-
- /*
- * Get SMM Dell signature
- */
- if (i8k_get_dell_signature() != 0) {
- printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
- } else {
- smm_found = 1;
- }
-
- /*
- * Get SMM BIOS version.
- */
- version = i8k_get_bios_version();
- if (version <= 0) {
- printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
- } else {
- smm_found = 1;
- buff[0] = (version >> 16) & 0xff;
- buff[1] = (version >> 8) & 0xff;
- buff[2] = (version) & 0xff;
- buff[3] = '\0';
+ char buff[4];
+ int version;
+
/*
- * If DMI BIOS version is unknown use SMM BIOS version.
+ * Get DMI information
*/
- if (bios_version[0] == '?') {
- strcpy(bios_version, buff);
+ if (!dmi_check_system(i8k_dmi_table)) {
+ if (!ignore_dmi && !force)
+ return -ENODEV;
+
+ printk(KERN_INFO "i8k: not running on a supported Dell system.\n");
+ printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+ i8k_get_dmi_data(DMI_SYS_VENDOR),
+ i8k_get_dmi_data(DMI_PRODUCT_NAME),
+ i8k_get_dmi_data(DMI_BIOS_VERSION));
}
+
+ strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version));
+
/*
- * Check if the two versions match.
+ * Get SMM Dell signature
*/
- if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
- printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
- buff, bios_version);
+ if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
+ i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
+ printk(KERN_ERR "i8k: unable to get SMM Dell signature\n");
+ if (!force)
+ return -ENODEV;
}
- }
- if (!smm_found && !force) {
- return -ENODEV;
- }
+ /*
+ * Get SMM BIOS version.
+ */
+ version = i8k_get_bios_version();
+ if (version <= 0) {
+ printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n");
+ } else {
+ buff[0] = (version >> 16) & 0xff;
+ buff[1] = (version >> 8) & 0xff;
+ buff[2] = (version) & 0xff;
+ buff[3] = '\0';
+ /*
+ * If DMI BIOS version is unknown use SMM BIOS version.
+ */
+ if (!dmi_get_system_info(DMI_BIOS_VERSION))
+ strlcpy(bios_version, buff, sizeof(bios_version));
+
+ /*
+ * Check if the two versions match.
+ */
+ if (strncmp(buff, bios_version, sizeof(bios_version)) != 0)
+ printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n",
+ buff, bios_version);
+ }
- return 0;
+ return 0;
}
-#ifdef MODULE
-static
-#endif
-int __init i8k_init(void)
+static int __init i8k_init(void)
{
- struct proc_dir_entry *proc_i8k;
-
- /* Are we running on an supported laptop? */
- if (i8k_probe() != 0) {
- return -ENODEV;
- }
-
- /* Register the proc entry */
- proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
- if (!proc_i8k) {
- return -ENOENT;
- }
- proc_i8k->proc_fops = &i8k_fops;
- proc_i8k->owner = THIS_MODULE;
-
- printk(KERN_INFO
- "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
- I8K_VERSION);
-
- return 0;
-}
+ struct proc_dir_entry *proc_i8k;
-#ifdef MODULE
-int init_module(void)
-{
- return i8k_init();
+ /* Are we running on an supported laptop? */
+ if (i8k_probe())
+ return -ENODEV;
+
+ /* Register the proc entry */
+ proc_i8k = create_proc_entry("i8k", 0, NULL);
+ if (!proc_i8k)
+ return -ENOENT;
+
+ proc_i8k->proc_fops = &i8k_fops;
+ proc_i8k->owner = THIS_MODULE;
+
+ printk(KERN_INFO
+ "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
+ I8K_VERSION);
+
+ return 0;
}
-void cleanup_module(void)
+static void __exit i8k_exit(void)
{
- /* Remove the proc entry */
- remove_proc_entry("i8k", NULL);
-
- printk(KERN_INFO "i8k: module unloaded\n");
+ remove_proc_entry("i8k", NULL);
}
-#endif
-/* end of file */
+module_init(i8k_init);
+module_exit(i8k_exit);
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c
index fd299d6c42a..cb8f4198e9a 100644
--- a/drivers/char/ip2/i2cmd.c
+++ b/drivers/char/ip2/i2cmd.c
@@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME
//static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING
//static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB
//static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB
-static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS
+//static UCHAR ct47[]={ 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS
//static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB
//static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB
//static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB
@@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW
// This routine sets the parameters of command 47 and returns a pointer to the
// appropriate structure.
//******************************************************************************
+#if 0
cmdSyntaxPtr
i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
{
@@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
pCM->cmd[6] = (unsigned char) (lflag >> 8);
return pCM;
}
+#endif /* 0 */
//******************************************************************************
// Function: i2cmdBaudDef(which, rate)
@@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
// This routine sets the parameters of commands 54 or 55 (according to the
// argument which), and returns a pointer to the appropriate structure.
//******************************************************************************
-cmdSyntaxPtr
+static cmdSyntaxPtr
i2cmdBaudDef(int which, unsigned short rate)
{
cmdSyntaxPtr pCM;
diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h
index c41728a8571..baa4e721b75 100644
--- a/drivers/char/ip2/i2cmd.h
+++ b/drivers/char/ip2/i2cmd.h
@@ -64,16 +64,6 @@ typedef struct _cmdSyntax
// directly from user-level
#define VAR 0x10 // This command is of variable length!
-//-----------------------------------
-// External declarations for i2cmd.c
-//-----------------------------------
-// Routine to set up parameters for the "define hot-key sequence" command. Since
-// there is more than one parameter to assign, we must use a function rather
-// than a macro (used usually).
-//
-extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag);
-extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate);
-
// Declarations for the global arrays used to bear the commands and their
// arguments.
//
@@ -433,6 +423,7 @@ static UCHAR cc02[];
#define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking
#define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking
+#if 0
// COMMAND 47: Send Protocol info via Unix flags:
// iflag = Unix tty t_iflag
// cflag = Unix tty t_cflag
@@ -441,6 +432,7 @@ static UCHAR cc02[];
// within these flags
//
#define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag)
+#endif /* 0 */
#define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl
#define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 3b8314b4249..cf0cd58d630 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -2691,16 +2691,6 @@ no_xon:
pCh->flags |= ASYNC_CHECK_CD;
}
-#ifdef XXX
-do_flags_thing: // This is a test, we don't do the flags thing
-
- if ( (cflag & CRTSCTS) ) {
- cflag |= 014000000000;
- }
- i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1,
- CMD_UNIX_FLAGS(iflag,cflag,lflag));
-#endif
-
service_it:
i2DrainOutput( pCh, 100 );
}
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 88d1ad656e9..e0a53570fea 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -45,6 +45,7 @@
#include <asm/semaphore.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/compat.h>
#define IPMI_DEVINTF_VERSION "v33"
@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode,
return rv;
}
+#ifdef CONFIG_COMPAT
+
+/*
+ * The following code contains code for supporting 32-bit compatible
+ * ioctls on 64-bit kernels. This allows running 32-bit apps on the
+ * 64-bit kernel
+ */
+#define COMPAT_IPMICTL_SEND_COMMAND \
+ _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
+#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \
+ _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
+#define COMPAT_IPMICTL_RECEIVE_MSG \
+ _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
+#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \
+ _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
+
+struct compat_ipmi_msg {
+ u8 netfn;
+ u8 cmd;
+ u16 data_len;
+ compat_uptr_t data;
+};
+
+struct compat_ipmi_req {
+ compat_uptr_t addr;
+ compat_uint_t addr_len;
+ compat_long_t msgid;
+ struct compat_ipmi_msg msg;
+};
+
+struct compat_ipmi_recv {
+ compat_int_t recv_type;
+ compat_uptr_t addr;
+ compat_uint_t addr_len;
+ compat_long_t msgid;
+ struct compat_ipmi_msg msg;
+};
+
+struct compat_ipmi_req_settime {
+ struct compat_ipmi_req req;
+ compat_int_t retries;
+ compat_uint_t retry_time_ms;
+};
+
+/*
+ * Define some helper functions for copying IPMI data
+ */
+static long get_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg __user *p32)
+{
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(p64->netfn, &p32->netfn) ||
+ __get_user(p64->cmd, &p32->cmd) ||
+ __get_user(p64->data_len, &p32->data_len) ||
+ __get_user(tmp, &p32->data))
+ return -EFAULT;
+ p64->data = compat_ptr(tmp);
+ return 0;
+}
+
+static long put_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg __user *p32)
+{
+ if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+ __put_user(p64->netfn, &p32->netfn) ||
+ __put_user(p64->cmd, &p32->cmd) ||
+ __put_user(p64->data_len, &p32->data_len))
+ return -EFAULT;
+ return 0;
+}
+
+static long get_compat_ipmi_req(struct ipmi_req *p64,
+ struct compat_ipmi_req __user *p32)
+{
+
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(tmp, &p32->addr) ||
+ __get_user(p64->addr_len, &p32->addr_len) ||
+ __get_user(p64->msgid, &p32->msgid) ||
+ get_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ p64->addr = compat_ptr(tmp);
+ return 0;
+}
+
+static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
+ struct compat_ipmi_req_settime __user *p32)
+{
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ get_compat_ipmi_req(&p64->req, &p32->req) ||
+ __get_user(p64->retries, &p32->retries) ||
+ __get_user(p64->retry_time_ms, &p32->retry_time_ms))
+ return -EFAULT;
+ return 0;
+}
+
+static long get_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv __user *p32)
+{
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(p64->recv_type, &p32->recv_type) ||
+ __get_user(tmp, &p32->addr) ||
+ __get_user(p64->addr_len, &p32->addr_len) ||
+ __get_user(p64->msgid, &p32->msgid) ||
+ get_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ p64->addr = compat_ptr(tmp);
+ return 0;
+}
+
+static long put_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv __user *p32)
+{
+ if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+ __put_user(p64->recv_type, &p32->recv_type) ||
+ __put_user(p64->addr_len, &p32->addr_len) ||
+ __put_user(p64->msgid, &p32->msgid) ||
+ put_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * Handle compatibility ioctls
+ */
+static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+ struct ipmi_file_private *priv = filep->private_data;
+
+ switch(cmd) {
+ case COMPAT_IPMICTL_SEND_COMMAND:
+ {
+ struct ipmi_req rp;
+
+ if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
+ return -EFAULT;
+
+ return handle_send_req(priv->user, &rp,
+ priv->default_retries,
+ priv->default_retry_time_ms);
+ }
+ case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
+ {
+ struct ipmi_req_settime sp;
+
+ if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
+ return -EFAULT;
+
+ return handle_send_req(priv->user, &sp.req,
+ sp.retries, sp.retry_time_ms);
+ }
+ case COMPAT_IPMICTL_RECEIVE_MSG:
+ case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
+ {
+ struct ipmi_recv *precv64, recv64;
+
+ if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ return -EFAULT;
+
+ precv64 = compat_alloc_user_space(sizeof(recv64));
+ if (copy_to_user(precv64, &recv64, sizeof(recv64)))
+ return -EFAULT;
+
+ rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
+ ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
+ ? IPMICTL_RECEIVE_MSG
+ : IPMICTL_RECEIVE_MSG_TRUNC),
+ (long) precv64);
+ if (rc != 0)
+ return rc;
+
+ if (copy_from_user(&recv64, precv64, sizeof(recv64)))
+ return -EFAULT;
+
+ if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ return -EFAULT;
+
+ return rc;
+ }
+ default:
+ return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
+ }
+}
+#endif
static struct file_operations ipmi_fops = {
.owner = THIS_MODULE,
.ioctl = ipmi_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_ipmi_ioctl,
+#endif
.open = ipmi_open,
.release = ipmi_release,
.fasync = ipmi_fasync,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 0c81652eaba..1813d0d198f 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void);
static int initialized = 0;
-static struct proc_dir_entry *proc_ipmi_root = NULL;
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_ipmi_root = NULL;
+#endif /* CONFIG_PROC_FS */
#define MAX_EVENTS_IN_QUEUE 25
@@ -124,11 +126,13 @@ struct ipmi_channel
unsigned char protocol;
};
+#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry
{
char *name;
struct ipmi_proc_entry *next;
};
+#endif
#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 8
@@ -156,10 +160,13 @@ struct ipmi_smi
struct ipmi_smi_handlers *handlers;
void *send_info;
+#ifdef CONFIG_PROC_FS
/* A list of proc entries for this interface. This does not
need a lock, only one thread creates it and only one thread
destroys it. */
+ spinlock_t proc_entry_lock;
struct ipmi_proc_entry *proc_entries;
+#endif
/* A table of sequence numbers for this interface. We use the
sequence numbers for IPMB messages that go out of the
@@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
read_proc_t *read_proc, write_proc_t *write_proc,
void *data, struct module *owner)
{
- struct proc_dir_entry *file;
int rv = 0;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *file;
struct ipmi_proc_entry *entry;
/* Create a list element. */
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
file->write_proc = write_proc;
file->owner = owner;
+ spin_lock(&smi->proc_entry_lock);
/* Stick it on the list. */
entry->next = smi->proc_entries;
smi->proc_entries = entry;
+ spin_unlock(&smi->proc_entry_lock);
}
+#endif /* CONFIG_PROC_FS */
return rv;
}
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
{
int rv = 0;
+#ifdef CONFIG_PROC_FS
sprintf(smi->proc_dir_name, "%d", num);
smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
if (!smi->proc_dir)
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
rv = ipmi_smi_add_proc_entry(smi, "version",
version_file_read_proc, NULL,
smi, THIS_MODULE);
+#endif /* CONFIG_PROC_FS */
return rv;
}
static void remove_proc_entries(ipmi_smi_t smi)
{
+#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry *entry;
+ spin_lock(&smi->proc_entry_lock);
while (smi->proc_entries) {
entry = smi->proc_entries;
smi->proc_entries = entry->next;
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi)
kfree(entry->name);
kfree(entry);
}
+ spin_unlock(&smi->proc_entry_lock);
remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
+#endif /* CONFIG_PROC_FS */
}
static int
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
new_intf->seq_table[j].seqid = 0;
}
new_intf->curr_seq = 0;
+#ifdef CONFIG_PROC_FS
+ spin_lock_init(&(new_intf->proc_entry_lock));
+#endif
spin_lock_init(&(new_intf->waiting_msgs_lock));
INIT_LIST_HEAD(&(new_intf->waiting_msgs));
spin_lock_init(&(new_intf->events_lock));
@@ -2747,16 +2767,13 @@ static struct timer_list ipmi_timer;
the queue and this silliness can go away. */
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
-static volatile int stop_operation = 0;
-static volatile int timer_stopped = 0;
+static atomic_t stop_operation;
static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
static void ipmi_timeout(unsigned long data)
{
- if (stop_operation) {
- timer_stopped = 1;
+ if (atomic_read(&stop_operation))
return;
- }
ticks_to_req_ev--;
if (ticks_to_req_ev == 0) {
@@ -2766,8 +2783,7 @@ static void ipmi_timeout(unsigned long data)
ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
- ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
- add_timer(&ipmi_timer);
+ mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
}
@@ -3089,6 +3105,7 @@ static int ipmi_init_msghandler(void)
ipmi_interfaces[i] = NULL;
}
+#ifdef CONFIG_PROC_FS
proc_ipmi_root = proc_mkdir("ipmi", NULL);
if (!proc_ipmi_root) {
printk(KERN_ERR PFX "Unable to create IPMI proc dir");
@@ -3096,6 +3113,7 @@ static int ipmi_init_msghandler(void)
}
proc_ipmi_root->owner = THIS_MODULE;
+#endif /* CONFIG_PROC_FS */
init_timer(&ipmi_timer);
ipmi_timer.data = 0;
@@ -3130,13 +3148,12 @@ static __exit void cleanup_ipmi(void)
/* Tell the timer to stop, then wait for it to stop. This avoids
problems with race conditions removing the timer here. */
- stop_operation = 1;
- while (!timer_stopped) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
+ atomic_inc(&stop_operation);
+ del_timer_sync(&ipmi_timer);
+#ifdef CONFIG_PROC_FS
remove_proc_entry(proc_ipmi_root->name, &proc_root);
+#endif /* CONFIG_PROC_FS */
initialized = 0;
@@ -3177,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
+EXPORT_SYMBOL(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index cb5cdc6f14b..f951c30236c 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -31,10 +31,13 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <asm/semaphore.h>
-#include <linux/kdev_t.h>
+#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
#include <linux/string.h>
+#include <linux/completion.h>
+#include <linux/kdev_t.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
@@ -44,6 +47,18 @@
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);
+/* Definitions for controlling power off (if the system supports it). It
+ * conveniently matches the IPMI chassis control values. */
+#define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */
+#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
+
+/* the IPMI data command */
+static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+
+/* parameter definition to allow user to flag power cycle */
+module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
+MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+
/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
@@ -75,10 +90,10 @@ static struct ipmi_recv_msg halt_recv_msg =
static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
{
- struct semaphore *sem = recv_msg->user_msg_data;
+ struct completion *comp = recv_msg->user_msg_data;
- if (sem)
- up(sem);
+ if (comp)
+ complete(comp);
}
static struct ipmi_user_hndl ipmi_poweroff_handler =
@@ -91,27 +106,27 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
- int rv;
- struct semaphore sem;
+ int rv;
+ struct completion comp;
- sema_init (&sem, 0);
+ init_completion(&comp);
- rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
+ rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp,
&halt_smi_msg, &halt_recv_msg, 0);
if (rv)
return rv;
- down (&sem);
+ wait_for_completion(&comp);
return halt_recv_msg.msg.data[0];
}
-/* We are in run-to-completion mode, no semaphore is desired. */
+/* We are in run-to-completion mode, no completion is desired. */
static int ipmi_request_in_rc_mode(ipmi_user_t user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
- int rv;
+ int rv;
rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
&halt_smi_msg, &halt_recv_msg, 0);
@@ -349,26 +364,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
+ powercyclefailed:
+ printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
+ ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
- data[0] = 0; /* Power down */
+ data[0] = poweroff_control;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
- printk(KERN_ERR PFX "Unable to send chassis powerdown message,"
- " IPMI error 0x%x\n", rv);
- goto out;
+ switch (poweroff_control) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ /* power cycle failed, default to power down */
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "cycle message, IPMI error 0x%x\n", rv);
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ goto powercyclefailed;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ default:
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "down message, IPMI error 0x%x\n", rv);
+ break;
+ }
}
- out:
return;
}
@@ -430,7 +457,8 @@ static void ipmi_po_new_smi(int if_num)
if (ready)
return;
- rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user);
+ rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
+ &ipmi_user);
if (rv) {
printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
rv);
@@ -509,21 +537,84 @@ static struct ipmi_smi_watcher smi_watcher =
};
+#ifdef CONFIG_PROC_FS
+/* displays properties to proc */
+static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
+ poweroff_control);
+}
+
+/* process property writes from proc */
+static int proc_write_chassctrl(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int rv = count;
+ unsigned int newval = 0;
+
+ sscanf(buffer, "%d", &newval);
+ switch (newval) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ printk(KERN_INFO PFX "power cycle is now enabled\n");
+ poweroff_control = newval;
+ break;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ break;
+
+ default:
+ rv = -EINVAL;
+ break;
+ }
+
+ return rv;
+}
+#endif /* CONFIG_PROC_FS */
+
/*
* Startup and shutdown functions.
*/
static int ipmi_poweroff_init (void)
{
- int rv;
+ int rv;
+ struct proc_dir_entry *file;
printk ("Copyright (C) 2004 MontaVista Software -"
" IPMI Powerdown via sys_reboot version "
IPMI_POWEROFF_VERSION ".\n");
+ switch (poweroff_control) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ printk(KERN_INFO PFX "Power cycle is enabled.\n");
+ break;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ default:
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ break;
+ }
+
rv = ipmi_smi_watcher_register(&smi_watcher);
- if (rv)
+ if (rv) {
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+ goto out_err;
+ }
+
+#ifdef CONFIG_PROC_FS
+ file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
+ if (!file) {
+ printk(KERN_ERR PFX "Unable to create proc power control\n");
+ } else {
+ file->nlink = 1;
+ file->read_proc = proc_read_chassctrl;
+ file->write_proc = proc_write_chassctrl;
+ file->owner = THIS_MODULE;
+ }
+#endif
+ out_err:
return rv;
}
@@ -532,6 +623,10 @@ static __exit void ipmi_poweroff_cleanup(void)
{
int rv;
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("poweroff_control", proc_ipmi_root);
+#endif
+
ipmi_smi_watcher_unregister(&smi_watcher);
if (ready) {
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 601c7fccb4c..1bbf507adda 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty)
}
-static int __init register_ioregion(void)
+static int __devinit register_ioregion(void)
{
int count, done=0;
for (count=0; count < BOARD_COUNT; count++ ) {
@@ -1771,7 +1771,7 @@ static int __init register_ioregion(void)
return done;
}
-static void __exit unregister_ioregion(void)
+static void unregister_ioregion(void)
{
int count;
for (count=0; count < BOARD_COUNT; count++ )
@@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = {
.tiocmset = isicom_tiocmset,
};
-static int __init register_drivers(void)
+static int __devinit register_drivers(void)
{
int error;
@@ -1834,7 +1834,7 @@ static int __init register_drivers(void)
return 0;
}
-static void __exit unregister_drivers(void)
+static void unregister_drivers(void)
{
int error = tty_unregister_driver(isicom_normal);
if (error)
@@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void)
put_tty_driver(isicom_normal);
}
-static int __init register_isr(void)
+static int __devinit register_isr(void)
{
int count, done=0;
unsigned long irqflags;
@@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void)
}
}
-static int __init isicom_init(void)
+static int __devinit isicom_init(void)
{
int card, channel, base;
struct isi_port * port;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index c02a21dbad5..52a073eee20 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -407,7 +407,6 @@ static unsigned long stli_eisamemprobeaddrs[] = {
};
static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
-int stli_eisaprobe = STLI_EISAPROBE;
/*
* Define the Stallion PCI vendor and device IDs.
@@ -4685,7 +4684,7 @@ static int stli_initbrds(void)
#ifdef MODULE
stli_argbrds();
#endif
- if (stli_eisaprobe)
+ if (STLI_EISAPROBE)
stli_findeisabrds();
#ifdef CONFIG_PCI
stli_findpcibrds();
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e3085b22a36..42187381506 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -23,7 +23,10 @@
#include <linux/devfs_fs_kernel.h>
#include <linux/ptrace.h>
#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
#include <linux/backing-dev.h>
+#include <linux/bootmem.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
return mmap_mem(file, vma);
}
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * Read memory corresponding to the old kernel.
+ */
+static ssize_t read_oldmem(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long pfn, offset;
+ size_t read = 0, csize;
+ int rc = 0;
+
+ while (count) {
+ pfn = *ppos / PAGE_SIZE;
+ if (pfn > saved_max_pfn)
+ return read;
+
+ offset = (unsigned long)(*ppos % PAGE_SIZE);
+ if (count > PAGE_SIZE - offset)
+ csize = PAGE_SIZE - offset;
+ else
+ csize = count;
+
+ rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
+ if (rc < 0)
+ return rc;
+ buf += csize;
+ *ppos += csize;
+ read += csize;
+ count -= csize;
+ }
+ return read;
+}
+#endif
+
extern long vread(char *buf, char *addr, unsigned long count);
extern long vwrite(char *buf, char *addr, unsigned long count);
@@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp)
#define read_full read_zero
#define open_mem open_port
#define open_kmem open_mem
+#define open_oldmem open_mem
static struct file_operations mem_fops = {
.llseek = memory_lseek,
@@ -770,6 +808,13 @@ static struct file_operations full_fops = {
.write = write_full,
};
+#ifdef CONFIG_CRASH_DUMP
+static struct file_operations oldmem_fops = {
+ .read = read_oldmem,
+ .open = open_oldmem,
+};
+#endif
+
static ssize_t kmsg_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
@@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp)
case 11:
filp->f_op = &kmsg_fops;
break;
+#ifdef CONFIG_CRASH_DUMP
+ case 12:
+ filp->f_op = &oldmem_fops;
+ break;
+#endif
default:
return -ENXIO;
}
@@ -854,6 +904,9 @@ static const struct {
{8, "random", S_IRUGO | S_IWUSR, &random_fops},
{9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
{11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops},
+#ifdef CONFIG_CRASH_DUMP
+ {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
+#endif
};
static struct class *mem_class;
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 3115d318b99..31cf84d6902 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8];
extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
-extern int tosh_init(void);
-extern int i8k_init(void);
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -314,12 +312,6 @@ static int __init misc_init(void)
#ifdef CONFIG_PMAC_PBOOK
pmu_device_init();
#endif
-#ifdef CONFIG_TOSHIBA
- tosh_init();
-#endif
-#ifdef CONFIG_I8K
- i8k_init();
-#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index ab00f51475d..613aed9e184 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
spin_unlock_irqrestore(&dsp_lock, flags);
}
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
- unsigned char ucValue)
+static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
+ unsigned char ucValue)
{
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
@@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
}
+#if 0
unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
unsigned uIndex)
{
@@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
return ucValue;
}
+#endif /* 0 */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
unsigned short *pIrqMap,
diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h
index 3e7d020d1bf..270431ca7da 100644
--- a/drivers/char/mwave/3780i.h
+++ b/drivers/char/mwave/3780i.h
@@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr);
void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr, unsigned short usValue);
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
- unsigned char ucValue);
-unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
- unsigned uIndex);
int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
unsigned short *pusIPCSource);
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index ab650cd6efc..d6c72e0934e 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct resource *pres;
-#endif
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
if ( pres == NULL ) retval = -EIO;
-#else
- retval = check_region(pSettings->usDspBaseIO, 16);
- if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
-#endif
+
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
retval = -EIO;
@@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
- BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE;
+ BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
@@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
goto exit_cleanup;
- } else {
- bDSPEnabled = TRUE;
}
EnableSRAM(pBDData);
@@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
exit_cleanup:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
- if (bDSPEnabled)
- dsp3780I_DisableDSP(pSettings);
if (bDSPPoweredUp)
smapi_set_DSP_power_state(FALSE);
if (bInterruptAllocated) {
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index b3dbff1cf96..5079beda69b 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -960,7 +960,7 @@ static char hdlc_unregister_fail[] __exitdata =
static void __exit n_hdlc_exit(void)
{
/* Release tty registration of line discipline */
- int status = tty_register_ldisc(N_HDLC, NULL);
+ int status = tty_unregister_ldisc(N_HDLC);
if (status)
printk(hdlc_unregister_fail, status);
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 3883073ab48..2291a87e8ad 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -200,7 +200,7 @@ static void __exit r3964_exit(void)
TRACE_M ("cleanup_module()");
- status=tty_register_ldisc(N_R3964, NULL);
+ status=tty_unregister_ldisc(N_R3964);
if(status!=0)
{
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index f63a3fd7ca6..1af733d0732 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -211,12 +211,13 @@ nvram_check_checksum(void)
return rv;
}
-void
+static void
__nvram_set_checksum(void)
{
mach_set_checksum();
}
+#if 0
void
nvram_set_checksum(void)
{
@@ -226,6 +227,7 @@ nvram_set_checksum(void)
__nvram_set_checksum();
spin_unlock_irqrestore(&rtc_lock, flags);
}
+#endif /* 0 */
/*
* The are the file operation function for user access to /dev/nvram
@@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte);
EXPORT_SYMBOL(nvram_write_byte);
EXPORT_SYMBOL(__nvram_check_checksum);
EXPORT_SYMBOL(nvram_check_checksum);
-EXPORT_SYMBOL(__nvram_set_checksum);
-EXPORT_SYMBOL(nvram_set_checksum);
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
index e8f3860f472..01987c6dc39 100644
--- a/drivers/char/rio/func.h
+++ b/drivers/char/rio/func.h
@@ -147,7 +147,6 @@ struct rio_info * rio_info_store( int cmd, struct rio_info * p);
extern int rio_pcicopy(char *src, char *dst, int n);
extern int rio_minor (struct tty_struct *tty);
extern int rio_ismodem (struct tty_struct *tty);
-extern void rio_udelay (int usecs);
extern void rio_start_card_running (struct Host * HostP);
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 763893e289b..7db3370f497 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -354,11 +354,6 @@ int rio_ismodem(struct tty_struct *tty)
}
-void rio_udelay (int usecs)
-{
- udelay (usecs);
-}
-
static int rio_set_real_termios (void *ptr)
{
int rv, modem;
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
index dca941ed10c..898a126ae3e 100644
--- a/drivers/char/rio/rioinit.c
+++ b/drivers/char/rio/rioinit.c
@@ -37,6 +37,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3";
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/string.h>
@@ -1560,14 +1561,14 @@ uint Slot;
INTERRUPT_DISABLE | BYTE_OPERATION |
SLOW_LINKS | SLOW_AT_BUS);
WBYTE(DpRamP->DpResetTpu, 0xFF);
- rio_udelay (3);
+ udelay(3);
rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n");
WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF |
INTERRUPT_DISABLE | BYTE_OPERATION |
SLOW_LINKS | SLOW_AT_BUS);
WBYTE(DpRamP->DpResetTpu, 0xFF);
- rio_udelay (3);
+ udelay(3);
break;
#ifdef FUTURE_RELEASE
case RIO_EISA:
@@ -1599,7 +1600,7 @@ uint Slot;
DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM;
DpRamP->DpResetInt = 0xFF;
DpRamP->DpResetTpu = 0xFF;
- rio_udelay (100);
+ udelay(100);
/* for (i=0; i<6000; i++); */
/* suspend( 3 ); */
break;
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index db655002671..78a321afdf4 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -524,16 +524,16 @@ riotclose(void *ptr)
register uint SysPort = dev;
struct ttystatics *tp; /* pointer to our ttystruct */
#endif
- struct Port *PortP =ptr; /* pointer to the port structure */
+ struct Port *PortP = ptr; /* pointer to the port structure */
int deleted = 0;
int try = -1; /* Disable the timeouts by setting them to -1 */
int repeat_this = -1; /* Congrats to those having 15 years of
uptime! (You get to break the driver.) */
- long end_time;
+ unsigned long end_time;
struct tty_struct * tty;
unsigned long flags;
int Modem;
- int rv =0;
+ int rv = 0;
rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum);
@@ -620,7 +620,7 @@ riotclose(void *ptr)
if (repeat_this -- <= 0) {
rv = -EINTR;
rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE );
+ RIOPreemptiveCmd(p, PortP, FCLOSE);
goto close_end;
}
rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -656,14 +656,12 @@ riotclose(void *ptr)
goto close_end;
}
-
-
/* Can't call RIOShortCommand with the port locked. */
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
- RIOPreemptiveCmd(p, PortP,FCLOSE);
- goto close_end;
+ RIOPreemptiveCmd(p, PortP, FCLOSE);
+ goto close_end;
}
if (!deleted)
@@ -698,7 +696,6 @@ riotclose(void *ptr)
*/
PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
-
#ifdef STATS
PortP->Stat.CloseCnt++;
#endif
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 5bcbeb0cb9a..f463d6baa68 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -161,6 +161,64 @@ static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
UPCI_AIOP_INTR_BIT_3
};
+static Byte_t RData[RDATASIZE] = {
+ 0x00, 0x09, 0xf6, 0x82,
+ 0x02, 0x09, 0x86, 0xfb,
+ 0x04, 0x09, 0x00, 0x0a,
+ 0x06, 0x09, 0x01, 0x0a,
+ 0x08, 0x09, 0x8a, 0x13,
+ 0x0a, 0x09, 0xc5, 0x11,
+ 0x0c, 0x09, 0x86, 0x85,
+ 0x0e, 0x09, 0x20, 0x0a,
+ 0x10, 0x09, 0x21, 0x0a,
+ 0x12, 0x09, 0x41, 0xff,
+ 0x14, 0x09, 0x82, 0x00,
+ 0x16, 0x09, 0x82, 0x7b,
+ 0x18, 0x09, 0x8a, 0x7d,
+ 0x1a, 0x09, 0x88, 0x81,
+ 0x1c, 0x09, 0x86, 0x7a,
+ 0x1e, 0x09, 0x84, 0x81,
+ 0x20, 0x09, 0x82, 0x7c,
+ 0x22, 0x09, 0x0a, 0x0a
+};
+
+static Byte_t RRegData[RREGDATASIZE] = {
+ 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
+ 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
+ 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
+ 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
+ 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
+ 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
+ 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
+ 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
+ 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
+ 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
+ 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
+ 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
+ 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
+};
+
+static CONTROLLER_T sController[CTL_SIZE] = {
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
+};
+
+static Byte_t sBitMapClrTbl[8] = {
+ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
+};
+
+static Byte_t sBitMapSetTbl[8] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
+};
+
+static int sClockPrescale = 0x14;
+
/*
* Line number is the ttySIx number (x), the Minor number. We
* assign them sequentially, starting at zero. The following
@@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
static void rp_start(struct tty_struct *tty);
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+ int ChanNum);
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
+static void sFlushRxFIFO(CHANNEL_T * ChP);
+static void sFlushTxFIFO(CHANNEL_T * ChP);
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+ int PeriodicOnly, int altChanRingIndicator,
+ int UPCIRingInd);
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ int IRQNum, Byte_t Frequency, int PeriodicOnly);
+static int sReadAiopID(ByteIO_t io);
+static int sReadAiopNumChan(WordIO_t io);
#ifdef MODULE
MODULE_AUTHOR("Theodore Ts'o");
@@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
* init's aiopic and serial port hardware.
* Inputs: i is the board number (0-n)
*/
-__init int register_PCI(int i, struct pci_dev *dev)
+static __init int register_PCI(int i, struct pci_dev *dev)
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
@@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void)
}
#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-static Byte_t RData[RDATASIZE] = {
- 0x00, 0x09, 0xf6, 0x82,
- 0x02, 0x09, 0x86, 0xfb,
- 0x04, 0x09, 0x00, 0x0a,
- 0x06, 0x09, 0x01, 0x0a,
- 0x08, 0x09, 0x8a, 0x13,
- 0x0a, 0x09, 0xc5, 0x11,
- 0x0c, 0x09, 0x86, 0x85,
- 0x0e, 0x09, 0x20, 0x0a,
- 0x10, 0x09, 0x21, 0x0a,
- 0x12, 0x09, 0x41, 0xff,
- 0x14, 0x09, 0x82, 0x00,
- 0x16, 0x09, 0x82, 0x7b,
- 0x18, 0x09, 0x8a, 0x7d,
- 0x1a, 0x09, 0x88, 0x81,
- 0x1c, 0x09, 0x86, 0x7a,
- 0x1e, 0x09, 0x84, 0x81,
- 0x20, 0x09, 0x82, 0x7c,
- 0x22, 0x09, 0x0a, 0x0a
-};
-
-static Byte_t RRegData[RREGDATASIZE] = {
- 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
- 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
- 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
- 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
- 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
- 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
- 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
- 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
- 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
- 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
- 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
- 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
- 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
-};
-
-CONTROLLER_T sController[CTL_SIZE] = {
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
-};
-
-Byte_t sBitMapClrTbl[8] = {
- 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
-};
-
-Byte_t sBitMapSetTbl[8] = {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
-};
-
-int sClockPrescale = 0x14;
-
/***************************************************************************
Function: sInitController
Purpose: Initialization of controller global registers and controller
@@ -2554,22 +2566,22 @@ Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
- int PeriodicOnly: TRUE if all interrupts except the periodic
+ int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
- FALSE is both the periodic interrupt and
+ 0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
- overidden, it is forced to a value of FALSE.
+ overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
- are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
- Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+ Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
@@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
-int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
- ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum,
- Byte_t Frequency, int PeriodicOnly)
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ int IRQNum, Byte_t Frequency, int PeriodicOnly)
{
int i;
ByteIO_t io;
@@ -2687,22 +2699,22 @@ Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
- int PeriodicOnly: TRUE if all interrupts except the periodic
+ int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
- FALSE is both the periodic interrupt and
+ 0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
- overidden, it is forced to a value of FALSE.
+ overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
- are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
- Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+ Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
@@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
-int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
- ByteIO_t * AiopIOList, int AiopIOListSize,
- WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
- int PeriodicOnly, int altChanRingIndicator,
- int UPCIRingInd)
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+ int PeriodicOnly, int altChanRingIndicator,
+ int UPCIRingInd)
{
int i;
ByteIO_t io;
@@ -2784,7 +2796,7 @@ Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
Warnings: No context switches are allowed while executing this function.
*/
-int sReadAiopID(ByteIO_t io)
+static int sReadAiopID(ByteIO_t io)
{
Byte_t AiopID; /* ID byte from AIOP */
@@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical
AIOP, otherwise it is an 8 channel.
Warnings: No context switches are allowed while executing this function.
*/
-int sReadAiopNumChan(WordIO_t io)
+static int sReadAiopNumChan(WordIO_t io)
{
Word_t x;
static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
@@ -2834,15 +2846,15 @@ Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
CHANNEL_T *ChP; Ptr to channel structure
int AiopNum; AIOP number within controller
int ChanNum; Channel number within AIOP
-Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
+Return: int: 1 if initialization succeeded, 0 if it fails because channel
number exceeds number of channels available in AIOP.
Comments: This function must be called before a channel can be used.
Warnings: No range checking on any of the parameters is done.
No context switches are allowed while executing this function.
*/
-int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
- int ChanNum)
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+ int ChanNum)
{
int i;
WordIO_t AiopIO;
@@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
int brd9600;
if (ChanNum >= CtlP->AiopNumChan[AiopNum])
- return (FALSE); /* exceeds num chans in AIOP */
+ return 0; /* exceeds num chans in AIOP */
/* Channel, AIOP, and controller identifiers */
ChP->CtlP = CtlP;
@@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
ChP->TxPrioBuf = ChOff + _TXP_BUF;
sEnRxProcessor(ChP); /* start the Rx processor */
- return (TRUE);
+ return 1;
}
/***************************************************************************
@@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function.
After calling this function a delay of 4 uS is required to ensure
that the receive processor is no longer processing this channel.
*/
-void sStopRxProcessor(CHANNEL_T * ChP)
+static void sStopRxProcessor(CHANNEL_T * ChP)
{
Byte_t R[4];
@@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
this function.
Warnings: No context switches are allowed while executing this function.
*/
-void sFlushRxFIFO(CHANNEL_T * ChP)
+static void sFlushRxFIFO(CHANNEL_T * ChP)
{
int i;
Byte_t Ch; /* channel number within AIOP */
- int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
+ int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
return; /* don't need to flush */
- RxFIFOEnabled = FALSE;
+ RxFIFOEnabled = 0;
if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
- RxFIFOEnabled = TRUE;
+ RxFIFOEnabled = 1;
sDisRxFIFO(ChP); /* disable it */
for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
sInB(ChP->IntChan); /* depends on bus i/o timing */
@@ -3056,18 +3068,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
this function.
Warnings: No context switches are allowed while executing this function.
*/
-void sFlushTxFIFO(CHANNEL_T * ChP)
+static void sFlushTxFIFO(CHANNEL_T * ChP)
{
int i;
Byte_t Ch; /* channel number within AIOP */
- int TxEnabled; /* TRUE if transmitter enabled */
+ int TxEnabled; /* 1 if transmitter enabled */
if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
return; /* don't need to flush */
- TxEnabled = FALSE;
+ TxEnabled = 0;
if (ChP->TxControl[3] & TX_ENABLE) {
- TxEnabled = TRUE;
+ TxEnabled = 1;
sDisTransmit(ChP); /* disable transmitter */
}
sStopRxProcessor(ChP); /* stop Rx processor */
@@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO.
Warnings: No context switches are allowed while executing this function.
*/
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
{
Byte_t DWBuf[4]; /* buffer for double word writes */
Word_t *WordPtr; /* must be far because Win SS != DS */
@@ -3158,7 +3170,7 @@ Comments: If an interrupt enable flag is set in Flags, that interrupt will be
enable channel interrupts. This would allow the global interrupt
status register to be used to determine which AIOPs need service.
*/
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
{
Byte_t Mask; /* Interrupt Mask Register */
@@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be
this channel's bit from being set in the AIOP's Interrupt Channel
Register.
*/
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
{
Byte_t Mask; /* Interrupt Mask Register */
@@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
}
}
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
{
sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
}
@@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
* Not an official SSCI function, but how to reset RocketModems.
* ISA bus version
*/
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
{
ByteIO_t addr;
Byte_t val;
@@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
* Not an official SSCI function, but how to reset RocketModems.
* PCI bus version
*/
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
{
ByteIO_t addr;
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 802687290ee..3a8bcc85bc1 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1130,46 +1130,6 @@ Warnings: This function writes the data byte without checking to see if
*/
#define sWriteTxByte(IO,DATA) sOutB(IO,DATA)
-int sInitController(CONTROLLER_T * CtlP,
- int CtlNum,
- ByteIO_t MudbacIO,
- ByteIO_t * AiopIOList,
- int AiopIOListSize,
- int IRQNum, Byte_t Frequency, int PeriodicOnly);
-
-int sPCIInitController(CONTROLLER_T * CtlP,
- int CtlNum,
- ByteIO_t * AiopIOList,
- int AiopIOListSize,
- WordIO_t ConfigIO,
- int IRQNum,
- Byte_t Frequency,
- int PeriodicOnly,
- int altChanRingIndicator, int UPCIRingInd);
-
-int sReadAiopID(ByteIO_t io);
-int sReadAiopNumChan(WordIO_t io);
-int sInitChan(CONTROLLER_T * CtlP,
- CHANNEL_T * ChP, int AiopNum, int ChanNum);
-Byte_t sGetRxErrStatus(CHANNEL_T * ChP);
-void sStopRxProcessor(CHANNEL_T * ChP);
-void sStopSWInFlowCtl(CHANNEL_T * ChP);
-void sFlushRxFIFO(CHANNEL_T * ChP);
-void sFlushTxFIFO(CHANNEL_T * ChP);
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
-
-extern Byte_t R[RDATASIZE];
-extern CONTROLLER_T sController[CTL_SIZE];
-extern Byte_t sIRQMap[16];
-extern Byte_t sBitMapClrTbl[8];
-extern Byte_t sBitMapSetTbl[8];
-extern int sClockPrescale;
-
/*
* Begin Linux specific definitions for the Rocketport driver
*
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index f59f7cbd525..af79805b557 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/vt_kern.h>
#include <linux/workqueue.h>
+#include <linux/kexec.h>
#include <asm/ptrace.h>
@@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = {
};
#endif /* CONFIG_VT */
+#ifdef CONFIG_KEXEC
+/* crashdump sysrq handler */
+static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
+ struct tty_struct *tty)
+{
+ crash_kexec(pt_regs);
+}
+static struct sysrq_key_op sysrq_crashdump_op = {
+ .handler = sysrq_handle_crashdump,
+ .help_msg = "Crashdump",
+ .action_msg = "Trigger a crashdump",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
/* reboot sysrq handler */
static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
struct tty_struct *tty)
@@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
it is handled specially on the sparc
and will never arrive */
/* b */ &sysrq_reboot_op,
-/* c */ NULL,
-/* d */ NULL,
+#ifdef CONFIG_KEXEC
+/* c */ &sysrq_crashdump_op,
+#else
+/* c */ NULL,
+#endif
+/* d */ NULL,
/* e */ &sysrq_term_op,
/* f */ &sysrq_moom_op,
/* g */ NULL,
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index 58e21fe4426..0c6f521abd0 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -73,16 +73,20 @@
#define TOSH_MINOR_DEV 181
-static int tosh_id = 0x0000;
-static int tosh_bios = 0x0000;
-static int tosh_date = 0x0000;
-static int tosh_sci = 0x0000;
-static int tosh_fan = 0;
-
-static int tosh_fn = 0;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
-module_param(tosh_fn, int, 0);
+static int tosh_fn;
+module_param_named(fn, tosh_fn, int, 0);
+MODULE_PARM_DESC(fn, "User specified Fn key detection port");
+static int tosh_id;
+static int tosh_bios;
+static int tosh_date;
+static int tosh_sci;
+static int tosh_fan;
static int tosh_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
@@ -359,7 +363,7 @@ static int tosh_get_machine_id(void)
unsigned long address;
id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa));
-
+
/* do we have a SCTTable machine identication number on our hands */
if (id==0xfc2f) {
@@ -424,7 +428,7 @@ static int tosh_probe(void)
}
/* call the Toshiba SCI support check routine */
-
+
regs.eax = 0xf0f0;
regs.ebx = 0x0000;
regs.ecx = 0x0000;
@@ -440,7 +444,7 @@ static int tosh_probe(void)
/* if we get this far then we are running on a Toshiba (probably)! */
tosh_sci = regs.edx & 0xffff;
-
+
/* next get the machine ID of the current laptop */
tosh_id = tosh_get_machine_id();
@@ -475,16 +479,15 @@ static int tosh_probe(void)
return 0;
}
-int __init tosh_init(void)
+static int __init toshiba_init(void)
{
int retval;
/* are we running on a Toshiba laptop */
- if (tosh_probe()!=0)
- return -EIO;
+ if (tosh_probe())
+ return -ENODEV;
- printk(KERN_INFO "Toshiba System Managment Mode driver v"
- TOSH_VERSION"\n");
+ printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n");
/* set the port to use for Fn status if not specified as a parameter */
if (tosh_fn==0x00)
@@ -492,12 +495,12 @@ int __init tosh_init(void)
/* register the device file */
retval = misc_register(&tosh_device);
- if(retval < 0)
+ if (retval < 0)
return retval;
#ifdef CONFIG_PROC_FS
/* register the proc entry */
- if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){
+ if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) {
misc_deregister(&tosh_device);
return -ENOMEM;
}
@@ -506,27 +509,12 @@ int __init tosh_init(void)
return 0;
}
-#ifdef MODULE
-int init_module(void)
-{
- return tosh_init();
-}
-
-void cleanup_module(void)
+static void __exit toshiba_exit(void)
{
- /* remove the proc entry */
-
remove_proc_entry("toshiba", NULL);
-
- /* unregister the device file */
-
misc_deregister(&tosh_device);
}
-#endif
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
-MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
-MODULE_DESCRIPTION("Toshiba laptop SMM driver");
-MODULE_SUPPORTED_DEVICE("toshiba");
+module_init(toshiba_init);
+module_exit(toshiba_exit);
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 8ce508b2986..854475c54f0 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -19,7 +19,7 @@
*
* Note, the TPM chip is not interrupt driven (only polling)
* and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
+ * calls to msleep.
*
*/
@@ -28,19 +28,16 @@
#include <linux/spinlock.h>
#include "tpm.h"
-#define TPM_MINOR 224 /* officially assigned */
-
-#define TPM_BUFSIZE 2048
-
-/* PCI configuration addresses */
-#define PCI_GEN_PMCON_1 0xA0
-#define PCI_GEN1_DEC 0xE4
-#define PCI_LPC_EN 0xE6
-#define PCI_GEN2_DEC 0xEC
+enum tpm_const {
+ TPM_MINOR = 224, /* officially assigned */
+ TPM_BUFSIZE = 2048,
+ TPM_NUM_DEVICES = 256,
+ TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
+};
static LIST_HEAD(tpm_chip_list);
static DEFINE_SPINLOCK(driver_lock);
-static int dev_mask[32];
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
static void user_reader_timeout(unsigned long ptr)
{
@@ -52,92 +49,17 @@ static void user_reader_timeout(unsigned long ptr)
up(&chip->buffer_mutex);
}
-void tpm_time_expired(unsigned long ptr)
-{
- int *exp = (int *) ptr;
- *exp = 1;
-}
-
-EXPORT_SYMBOL_GPL(tpm_time_expired);
-
-/*
- * Initialize the LPC bus and enable the TPM ports
- */
-int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base)
-{
- u32 lpcenable, tmp;
- int is_lpcm = 0;
-
- switch (pci_dev->vendor) {
- case PCI_VENDOR_ID_INTEL:
- switch (pci_dev->device) {
- case PCI_DEVICE_ID_INTEL_82801CA_12:
- case PCI_DEVICE_ID_INTEL_82801DB_12:
- is_lpcm = 1;
- break;
- }
- /* init ICH (enable LPC) */
- pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable);
- lpcenable |= 0x20000000;
- pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable);
-
- if (is_lpcm) {
- pci_read_config_dword(pci_dev, PCI_GEN1_DEC,
- &lpcenable);
- if ((lpcenable & 0x20000000) == 0) {
- dev_err(&pci_dev->dev,
- "cannot enable LPC\n");
- return -ENODEV;
- }
- }
-
- /* initialize TPM registers */
- pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp);
-
- if (!is_lpcm)
- tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0);
- else
- tmp =
- (tmp & 0xFFFF0000) | (base & 0xFFF0) |
- 0x00000001;
-
- pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp);
-
- if (is_lpcm) {
- pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1,
- &tmp);
- tmp |= 0x00000004; /* enable CLKRUN */
- pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1,
- tmp);
- }
- tpm_write_index(0x0D, 0x55); /* unlock 4F */
- tpm_write_index(0x0A, 0x00); /* int disable */
- tpm_write_index(0x08, base); /* base addr lo */
- tpm_write_index(0x09, (base & 0xFF00) >> 8); /* base addr hi */
- tpm_write_index(0x0D, 0xAA); /* lock 4F */
- break;
- case PCI_VENDOR_ID_AMD:
- /* nothing yet */
- break;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_lpc_bus_init);
-
/*
* Internal kernel interface to transmit TPM commands
*/
static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
size_t bufsiz)
{
- ssize_t len;
+ ssize_t rc;
u32 count;
- __be32 *native_size;
+ unsigned long stop;
- native_size = (__force __be32 *) (buf + 2);
- count = be32_to_cpu(*native_size);
+ count = be32_to_cpu(*((__be32 *) (buf + 2)));
if (count == 0)
return -ENODATA;
@@ -149,53 +71,49 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
down(&chip->tpm_mutex);
- if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+ if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
dev_err(&chip->pci_dev->dev,
- "tpm_transmit: tpm_send: error %zd\n", len);
- return len;
+ "tpm_transmit: tpm_send: error %zd\n", rc);
+ goto out;
}
- down(&chip->timer_manipulation_mutex);
- chip->time_expired = 0;
- init_timer(&chip->device_timer);
- chip->device_timer.function = tpm_time_expired;
- chip->device_timer.expires = jiffies + 2 * 60 * HZ;
- chip->device_timer.data = (unsigned long) &chip->time_expired;
- add_timer(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
-
+ stop = jiffies + 2 * 60 * HZ;
do {
u8 status = inb(chip->vendor->base + 1);
if ((status & chip->vendor->req_complete_mask) ==
chip->vendor->req_complete_val) {
- down(&chip->timer_manipulation_mutex);
- del_singleshot_timer_sync(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
goto out_recv;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+
+ if ((status == chip->vendor->req_canceled)) {
+ dev_err(&chip->pci_dev->dev, "Operation Canceled\n");
+ rc = -ECANCELED;
+ goto out;
+ }
+
+ msleep(TPM_TIMEOUT); /* CHECK */
rmb();
- } while (!chip->time_expired);
+ } while (time_before(jiffies, stop));
chip->vendor->cancel(chip);
- dev_err(&chip->pci_dev->dev, "Time expired\n");
- up(&chip->tpm_mutex);
- return -EIO;
+ dev_err(&chip->pci_dev->dev, "Operation Timed out\n");
+ rc = -ETIME;
+ goto out;
out_recv:
- len = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
- if (len < 0)
+ rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+ if (rc < 0)
dev_err(&chip->pci_dev->dev,
- "tpm_transmit: tpm_recv: error %zd\n", len);
+ "tpm_transmit: tpm_recv: error %zd\n", rc);
+out:
up(&chip->tpm_mutex);
- return len;
+ return rc;
}
#define TPM_DIGEST_SIZE 20
#define CAP_PCR_RESULT_SIZE 18
-static u8 cap_pcr[] = {
+static const u8 cap_pcr[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -205,75 +123,94 @@ static u8 cap_pcr[] = {
};
#define READ_PCR_RESULT_SIZE 30
-static u8 pcrread[] = {
+static const u8 pcrread[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 14, /* length */
0, 0, 0, 21, /* TPM_ORD_PcrRead */
0, 0, 0, 0 /* PCR index */
};
-static ssize_t show_pcrs(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
u8 data[READ_PCR_RESULT_SIZE];
ssize_t len;
- int i, j, index, num_pcrs;
+ int i, j, num_pcrs;
+ __be32 index;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
memcpy(data, cap_pcr, sizeof(cap_pcr));
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < CAP_PCR_RESULT_SIZE)
- return len;
+ < CAP_PCR_RESULT_SIZE) {
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+ "attempting to determine the number of PCRS\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ return 0;
+ }
- num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14)));
+ num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
for (i = 0; i < num_pcrs; i++) {
memcpy(data, pcrread, sizeof(pcrread));
index = cpu_to_be32(i);
memcpy(data + 10, &index, 4);
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < READ_PCR_RESULT_SIZE)
- return len;
+ < READ_PCR_RESULT_SIZE){
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred"
+ " attempting to read PCR %d of %d\n",
+ be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs);
+ goto out;
+ }
str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", *(data + 10 + j));
str += sprintf(str, "\n");
}
+out:
return str - buf;
}
-
-static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pcrs);
#define READ_PUBEK_RESULT_SIZE 314
-static u8 readpubek[] = {
+static const u8 readpubek[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 30, /* length */
0, 0, 0, 124, /* TPM_ORD_ReadPubek */
};
-static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- u8 data[READ_PUBEK_RESULT_SIZE];
+ u8 *data;
ssize_t len;
- __be32 *native_val;
- int i;
+ int i, rc;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
+ data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
memcpy(data, readpubek, sizeof(readpubek));
memset(data + sizeof(readpubek), 0, 20); /* zero nonce */
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- READ_PUBEK_RESULT_SIZE)
- return len;
+ if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
+ READ_PUBEK_RESULT_SIZE) {
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+ "attempting to read the PUBEK\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ rc = 0;
+ goto out;
+ }
/*
ignore header 10 bytes
@@ -286,8 +223,6 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
ignore checksum 20 bytes
*/
- native_val = (__force __be32 *) (data + 34);
-
str +=
sprintf(str,
"Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -298,21 +233,23 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
data[15], data[16], data[17], data[22], data[23],
data[24], data[25], data[26], data[27], data[28],
data[29], data[30], data[31], data[32], data[33],
- be32_to_cpu(*native_val)
- );
+ be32_to_cpu(*((__be32 *) (data + 34))));
for (i = 0; i < 256; i++) {
- str += sprintf(str, "%02X ", data[i + 39]);
+ str += sprintf(str, "%02X ", data[i + 38]);
if ((i + 1) % 16 == 0)
str += sprintf(str, "\n");
}
- return str - buf;
+ rc = str - buf;
+out:
+ kfree(data);
+ return rc;
}
-static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pubek);
#define CAP_VER_RESULT_SIZE 18
-static u8 cap_version[] = {
+static const u8 cap_version[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 18, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -321,7 +258,7 @@ static u8 cap_version[] = {
};
#define CAP_MANUFACTURER_RESULT_SIZE 18
-static u8 cap_manufacturer[] = {
+static const u8 cap_manufacturer[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -330,14 +267,15 @@ static u8 cap_manufacturer[] = {
0, 0, 1, 3
};
-static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- u8 data[READ_PUBEK_RESULT_SIZE];
+ u8 data[sizeof(cap_manufacturer)];
ssize_t len;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
@@ -348,7 +286,7 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
return len;
str += sprintf(str, "Manufacturer: 0x%x\n",
- be32_to_cpu(*(data + 14)));
+ be32_to_cpu(*((__be32 *) (data + 14))));
memcpy(data, cap_version, sizeof(cap_version));
@@ -363,8 +301,20 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
return str - buf;
}
+EXPORT_SYMBOL_GPL(tpm_show_caps);
+
+ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return 0;
+
+ chip->vendor->cancel(chip);
+ return count;
+}
+EXPORT_SYMBOL_GPL(tpm_store_cancel);
-static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL);
/*
* Device file system interface to the TPM
@@ -422,24 +372,15 @@ EXPORT_SYMBOL_GPL(tpm_open);
int tpm_release(struct inode *inode, struct file *file)
{
struct tpm_chip *chip = file->private_data;
-
- file->private_data = NULL;
spin_lock(&driver_lock);
+ file->private_data = NULL;
chip->num_opens--;
- spin_unlock(&driver_lock);
-
- down(&chip->timer_manipulation_mutex);
- if (timer_pending(&chip->user_read_timer))
- del_singleshot_timer_sync(&chip->user_read_timer);
- else if (timer_pending(&chip->device_timer))
- del_singleshot_timer_sync(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
-
- kfree(chip->data_buffer);
+ del_singleshot_timer_sync(&chip->user_read_timer);
atomic_set(&chip->data_pending, 0);
-
pci_dev_put(chip->pci_dev);
+ kfree(chip->data_buffer);
+ spin_unlock(&driver_lock);
return 0;
}
@@ -453,10 +394,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
/* cannot perform a write until the read has cleared
either via tpm_read or a user_read_timer timeout */
- while (atomic_read(&chip->data_pending) != 0) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
- }
+ while (atomic_read(&chip->data_pending) != 0)
+ msleep(TPM_TIMEOUT);
down(&chip->buffer_mutex);
@@ -476,13 +415,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
up(&chip->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
- down(&chip->timer_manipulation_mutex);
- init_timer(&chip->user_read_timer);
- chip->user_read_timer.function = user_reader_timeout;
- chip->user_read_timer.data = (unsigned long) chip;
- chip->user_read_timer.expires = jiffies + (60 * HZ);
- add_timer(&chip->user_read_timer);
- up(&chip->timer_manipulation_mutex);
+ mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
return in_size;
}
@@ -493,29 +426,19 @@ ssize_t tpm_read(struct file * file, char __user * buf,
size_t size, loff_t * off)
{
struct tpm_chip *chip = file->private_data;
- int ret_size = -ENODATA;
+ int ret_size;
- if (atomic_read(&chip->data_pending) != 0) { /* Result available */
- down(&chip->timer_manipulation_mutex);
- del_singleshot_timer_sync(&chip->user_read_timer);
- up(&chip->timer_manipulation_mutex);
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ ret_size = atomic_read(&chip->data_pending);
+ atomic_set(&chip->data_pending, 0);
+ if (ret_size > 0) { /* relay data */
+ if (size < ret_size)
+ ret_size = size;
down(&chip->buffer_mutex);
-
- ret_size = atomic_read(&chip->data_pending);
- atomic_set(&chip->data_pending, 0);
-
- if (ret_size == 0) /* timeout just occurred */
- ret_size = -ETIME;
- else if (ret_size > 0) { /* relay data */
- if (size < ret_size)
- ret_size = size;
-
- if (copy_to_user((void __user *) buf,
- chip->data_buffer, ret_size)) {
- ret_size = -EFAULT;
- }
- }
+ if (copy_to_user
+ ((void __user *) buf, chip->data_buffer, ret_size))
+ ret_size = -EFAULT;
up(&chip->buffer_mutex);
}
@@ -541,14 +464,13 @@ void __devexit tpm_remove(struct pci_dev *pci_dev)
pci_set_drvdata(pci_dev, NULL);
misc_deregister(&chip->vendor->miscdev);
+ kfree(&chip->vendor->miscdev.name);
- device_remove_file(&pci_dev->dev, &dev_attr_pubek);
- device_remove_file(&pci_dev->dev, &dev_attr_pcrs);
- device_remove_file(&pci_dev->dev, &dev_attr_caps);
+ sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
pci_disable_device(pci_dev);
- dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32));
+ dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
kfree(chip);
@@ -590,10 +512,6 @@ int tpm_pm_resume(struct pci_dev *pci_dev)
if (chip == NULL)
return -ENODEV;
- spin_lock(&driver_lock);
- tpm_lpc_bus_init(pci_dev, chip->vendor->base);
- spin_unlock(&driver_lock);
-
return 0;
}
@@ -609,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
int tpm_register_hardware(struct pci_dev *pci_dev,
struct tpm_vendor_specific *entry)
{
- char devname[7];
+#define DEVNAME_SIZE 7
+
+ char *devname;
struct tpm_chip *chip;
int i, j;
@@ -622,17 +542,21 @@ int tpm_register_hardware(struct pci_dev *pci_dev,
init_MUTEX(&chip->buffer_mutex);
init_MUTEX(&chip->tpm_mutex);
- init_MUTEX(&chip->timer_manipulation_mutex);
INIT_LIST_HEAD(&chip->list);
+ init_timer(&chip->user_read_timer);
+ chip->user_read_timer.function = user_reader_timeout;
+ chip->user_read_timer.data = (unsigned long) chip;
+
chip->vendor = entry;
chip->dev_num = -1;
- for (i = 0; i < 32; i++)
- for (j = 0; j < 8; j++)
+ for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
+ for (j = 0; j < 8 * sizeof(int); j++)
if ((dev_mask[i] & (1 << j)) == 0) {
- chip->dev_num = i * 32 + j;
+ chip->dev_num =
+ i * TPM_NUM_MASK_ENTRIES + j;
dev_mask[i] |= 1 << j;
goto dev_num_search_complete;
}
@@ -648,7 +572,8 @@ dev_num_search_complete:
else
chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
- snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
+ devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+ scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
chip->vendor->miscdev.name = devname;
chip->vendor->miscdev.dev = &(pci_dev->dev);
@@ -665,31 +590,20 @@ dev_num_search_complete:
return -ENODEV;
}
+ spin_lock(&driver_lock);
+
pci_set_drvdata(pci_dev, chip);
list_add(&chip->list, &tpm_chip_list);
- device_create_file(&pci_dev->dev, &dev_attr_pubek);
- device_create_file(&pci_dev->dev, &dev_attr_pcrs);
- device_create_file(&pci_dev->dev, &dev_attr_caps);
-
- return 0;
-}
+ spin_unlock(&driver_lock);
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
+ sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
-static int __init init_tpm(void)
-{
return 0;
}
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index de0c796fce8..373b41f6b46 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -25,23 +25,38 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
-#define TPM_TIMEOUT msecs_to_jiffies(5)
+enum tpm_timeout {
+ TPM_TIMEOUT = 5, /* msecs */
+};
/* TPM addresses */
-#define TPM_ADDR 0x4E
-#define TPM_DATA 0x4F
+enum tpm_addr {
+ TPM_SUPERIO_ADDR = 0x2E,
+ TPM_ADDR = 0x4E,
+};
+
+extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
+ const char *, size_t);
struct tpm_chip;
struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
+ u8 req_canceled;
u16 base; /* TPM base address */
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
struct miscdevice miscdev;
+ struct attribute_group *attr_group;
};
struct tpm_chip {
@@ -58,29 +73,24 @@ struct tpm_chip {
struct timer_list user_read_timer; /* user needs to claim result */
struct semaphore tpm_mutex; /* tpm is processing */
- struct timer_list device_timer; /* tpm is processing */
- struct semaphore timer_manipulation_mutex;
struct tpm_vendor_specific *vendor;
struct list_head list;
};
-static inline int tpm_read_index(int index)
+static inline int tpm_read_index(int base, int index)
{
- outb(index, TPM_ADDR);
- return inb(TPM_DATA) & 0xFF;
+ outb(index, base);
+ return inb(base+1) & 0xFF;
}
-static inline void tpm_write_index(int index, int value)
+static inline void tpm_write_index(int base, int index, int value)
{
- outb(index, TPM_ADDR);
- outb(value & 0xFF, TPM_DATA);
+ outb(index, base);
+ outb(value & 0xFF, base+1);
}
-extern void tpm_time_expired(unsigned long);
-extern int tpm_lpc_bus_init(struct pci_dev *, u16);
-
extern int tpm_register_hardware(struct pci_dev *,
struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index f9333e729b6..cc2cc77fd17 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -22,17 +22,23 @@
#include "tpm.h"
/* Atmel definitions */
-#define TPM_ATML_BASE 0x400
+enum tpm_atmel_addr {
+ TPM_ATMEL_BASE_ADDR_LO = 0x08,
+ TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
/* write status bits */
-#define ATML_STATUS_ABORT 0x01
-#define ATML_STATUS_LASTBYTE 0x04
-
+enum tpm_atmel_write_status {
+ ATML_STATUS_ABORT = 0x01,
+ ATML_STATUS_LASTBYTE = 0x04
+};
/* read status bits */
-#define ATML_STATUS_BUSY 0x01
-#define ATML_STATUS_DATA_AVAIL 0x02
-#define ATML_STATUS_REWRITE 0x04
-
+enum tpm_atmel_read_status {
+ ATML_STATUS_BUSY = 0x01,
+ ATML_STATUS_DATA_AVAIL = 0x02,
+ ATML_STATUS_REWRITE = 0x04,
+ ATML_STATUS_READY = 0x08
+};
static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
{
@@ -121,13 +127,29 @@ static struct file_operations atmel_ops = {
.release = tpm_release,
};
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* atmel_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
static struct tpm_vendor_specific tpm_atmel = {
.recv = tpm_atml_recv,
.send = tpm_atml_send,
.cancel = tpm_atml_cancel,
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
.req_complete_val = ATML_STATUS_DATA_AVAIL,
- .base = TPM_ATML_BASE,
+ .req_canceled = ATML_STATUS_READY,
+ .attr_group = &atmel_attr_grp,
.miscdev = { .fops = &atmel_ops, },
};
@@ -136,27 +158,29 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
{
u8 version[4];
int rc = 0;
+ int lo, hi;
if (pci_enable_device(pci_dev))
return -EIO;
- if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
- rc = -ENODEV;
- goto out_err;
- }
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+ tpm_atmel.base = (hi<<8)|lo;
+ dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
/* verify that it is an Atmel part */
- if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
- || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
+ if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
+ || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
rc = -ENODEV;
goto out_err;
}
/* query chip for its version number */
- if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
- version[1] = tpm_read_index(0x01);
- version[2] = tpm_read_index(0x02);
- version[3] = tpm_read_index(0x03);
+ if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
+ version[1] = tpm_read_index(TPM_ADDR, 0x01);
+ version[2] = tpm_read_index(TPM_ADDR, 0x02);
+ version[3] = tpm_read_index(TPM_ADDR, 0x03);
} else {
dev_info(&pci_dev->dev, "version query failed\n");
rc = -ENODEV;
@@ -183,6 +207,7 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+ {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
{0,}
};
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 9cce833a092..b4127348c06 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -22,43 +22,52 @@
#include "tpm.h"
/* National definitions */
-#define TPM_NSC_BASE 0x360
-#define TPM_NSC_IRQ 0x07
+enum tpm_nsc_addr{
+ TPM_NSC_IRQ = 0x07,
+ TPM_NSC_BASE0_HI = 0x60,
+ TPM_NSC_BASE0_LO = 0x61,
+ TPM_NSC_BASE1_HI = 0x62,
+ TPM_NSC_BASE1_LO = 0x63
+};
-#define NSC_LDN_INDEX 0x07
-#define NSC_SID_INDEX 0x20
-#define NSC_LDC_INDEX 0x30
-#define NSC_DIO_INDEX 0x60
-#define NSC_CIO_INDEX 0x62
-#define NSC_IRQ_INDEX 0x70
-#define NSC_ITS_INDEX 0x71
+enum tpm_nsc_index {
+ NSC_LDN_INDEX = 0x07,
+ NSC_SID_INDEX = 0x20,
+ NSC_LDC_INDEX = 0x30,
+ NSC_DIO_INDEX = 0x60,
+ NSC_CIO_INDEX = 0x62,
+ NSC_IRQ_INDEX = 0x70,
+ NSC_ITS_INDEX = 0x71
+};
-#define NSC_STATUS 0x01
-#define NSC_COMMAND 0x01
-#define NSC_DATA 0x00
+enum tpm_nsc_status_loc {
+ NSC_STATUS = 0x01,
+ NSC_COMMAND = 0x01,
+ NSC_DATA = 0x00
+};
/* status bits */
-#define NSC_STATUS_OBF 0x01 /* output buffer full */
-#define NSC_STATUS_IBF 0x02 /* input buffer full */
-#define NSC_STATUS_F0 0x04 /* F0 */
-#define NSC_STATUS_A2 0x08 /* A2 */
-#define NSC_STATUS_RDY 0x10 /* ready to receive command */
-#define NSC_STATUS_IBR 0x20 /* ready to receive data */
+enum tpm_nsc_status {
+ NSC_STATUS_OBF = 0x01, /* output buffer full */
+ NSC_STATUS_IBF = 0x02, /* input buffer full */
+ NSC_STATUS_F0 = 0x04, /* F0 */
+ NSC_STATUS_A2 = 0x08, /* A2 */
+ NSC_STATUS_RDY = 0x10, /* ready to receive command */
+ NSC_STATUS_IBR = 0x20 /* ready to receive data */
+};
/* command bits */
-#define NSC_COMMAND_NORMAL 0x01 /* normal mode */
-#define NSC_COMMAND_EOC 0x03
-#define NSC_COMMAND_CANCEL 0x22
-
+enum tpm_nsc_cmd_mode {
+ NSC_COMMAND_NORMAL = 0x01, /* normal mode */
+ NSC_COMMAND_EOC = 0x03,
+ NSC_COMMAND_CANCEL = 0x22
+};
/*
* Wait for a certain status to appear
*/
static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
{
- int expired = 0;
- struct timer_list status_timer =
- TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ,
- (unsigned long) &expired);
+ unsigned long stop;
/* status immediately available check */
*data = inb(chip->vendor->base + NSC_STATUS);
@@ -66,17 +75,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
return 0;
/* wait for status */
- add_timer(&status_timer);
+ stop = jiffies + 10 * HZ;
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+ msleep(TPM_TIMEOUT);
*data = inb(chip->vendor->base + 1);
- if ((*data & mask) == val) {
- del_singleshot_timer_sync(&status_timer);
+ if ((*data & mask) == val)
return 0;
- }
}
- while (!expired);
+ while (time_before(jiffies, stop));
return -EBUSY;
}
@@ -84,10 +90,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
static int nsc_wait_for_ready(struct tpm_chip *chip)
{
int status;
- int expired = 0;
- struct timer_list status_timer =
- TIMER_INITIALIZER(tpm_time_expired, jiffies + 100,
- (unsigned long) &expired);
+ unsigned long stop;
/* status immediately available check */
status = inb(chip->vendor->base + NSC_STATUS);
@@ -97,19 +100,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
return 0;
/* wait for status */
- add_timer(&status_timer);
+ stop = jiffies + 100;
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+ msleep(TPM_TIMEOUT);
status = inb(chip->vendor->base + NSC_STATUS);
if (status & NSC_STATUS_OBF)
status = inb(chip->vendor->base + NSC_DATA);
- if (status & NSC_STATUS_RDY) {
- del_singleshot_timer_sync(&status_timer);
+ if (status & NSC_STATUS_RDY)
return 0;
- }
}
- while (!expired);
+ while (time_before(jiffies, stop));
dev_info(&chip->pci_dev->dev, "wait for ready failed\n");
return -EBUSY;
@@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
*p = inb(chip->vendor->base + NSC_DATA);
}
- if ((data & NSC_STATUS_F0) == 0) {
+ if ((data & NSC_STATUS_F0) == 0 &&
+ (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
dev_err(&chip->pci_dev->dev, "F0 not set\n");
return -EIO;
}
@@ -228,100 +229,95 @@ static struct file_operations nsc_ops = {
.release = tpm_release,
};
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute * nsc_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
static struct tpm_vendor_specific tpm_nsc = {
.recv = tpm_nsc_recv,
.send = tpm_nsc_send,
.cancel = tpm_nsc_cancel,
.req_complete_mask = NSC_STATUS_OBF,
.req_complete_val = NSC_STATUS_OBF,
- .base = TPM_NSC_BASE,
+ .req_canceled = NSC_STATUS_RDY,
+ .attr_group = &nsc_attr_grp,
.miscdev = { .fops = &nsc_ops, },
-
};
static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
int rc = 0;
+ int lo, hi;
+ int nscAddrBase = TPM_ADDR;
+
if (pci_enable_device(pci_dev))
return -EIO;
- if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) {
- rc = -ENODEV;
- goto out_err;
- }
+ /* select PM channel 1 */
+ tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
/* verify that it is a National part (SID) */
- if (tpm_read_index(NSC_SID_INDEX) != 0xEF) {
- rc = -ENODEV;
- goto out_err;
+ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+ nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
+ (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
+ if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
+ rc = -ENODEV;
+ goto out_err;
+ }
}
+ hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+ lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+ tpm_nsc.base = (hi<<8) | lo;
+
dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
dev_dbg(&pci_dev->dev,
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
- tpm_read_index(0x07), tpm_read_index(0x20),
- tpm_read_index(0x27));
+ tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
+ tpm_read_index(nscAddrBase,0x27));
dev_dbg(&pci_dev->dev,
"NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
- tpm_read_index(0x21), tpm_read_index(0x25),
- tpm_read_index(0x26), tpm_read_index(0x28));
+ tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
+ tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
- (tpm_read_index(0x60) << 8) | tpm_read_index(0x61));
+ (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
- (tpm_read_index(0x62) << 8) | tpm_read_index(0x63));
+ (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
- tpm_read_index(0x70));
+ tpm_read_index(nscAddrBase,0x70));
dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
- tpm_read_index(0x71));
+ tpm_read_index(nscAddrBase,0x71));
dev_dbg(&pci_dev->dev,
"NSC DMA channel select0 0x%x, select1 0x%x\n",
- tpm_read_index(0x74), tpm_read_index(0x75));
+ tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
dev_dbg(&pci_dev->dev,
"NSC Config "
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
- tpm_read_index(0xF0), tpm_read_index(0xF1),
- tpm_read_index(0xF2), tpm_read_index(0xF3),
- tpm_read_index(0xF4), tpm_read_index(0xF5),
- tpm_read_index(0xF6), tpm_read_index(0xF7),
- tpm_read_index(0xF8), tpm_read_index(0xF9));
+ tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
+ tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
+ tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
+ tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
+ tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
dev_info(&pci_dev->dev,
- "NSC PC21100 TPM revision %d\n",
- tpm_read_index(0x27) & 0x1F);
-
- if (tpm_read_index(NSC_LDC_INDEX) == 0)
- dev_info(&pci_dev->dev, ": NSC TPM not active\n");
-
- /* select PM channel 1 */
- tpm_write_index(NSC_LDN_INDEX, 0x12);
- tpm_read_index(NSC_LDN_INDEX);
-
- /* disable the DPM module */
- tpm_write_index(NSC_LDC_INDEX, 0);
- tpm_read_index(NSC_LDC_INDEX);
-
- /* set the data register base addresses */
- tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8);
- tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE);
- tpm_read_index(NSC_DIO_INDEX);
- tpm_read_index(NSC_DIO_INDEX + 1);
-
- /* set the command register base addresses */
- tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8);
- tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1));
- tpm_read_index(NSC_DIO_INDEX);
- tpm_read_index(NSC_DIO_INDEX + 1);
-
- /* set the interrupt number to be used for the host interface */
- tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ);
- tpm_write_index(NSC_ITS_INDEX, 0x00);
- tpm_read_index(NSC_IRQ_INDEX);
+ "NSC TPM revision %d\n",
+ tpm_read_index(nscAddrBase, 0x27) & 0x1F);
/* enable the DPM module */
- tpm_write_index(NSC_LDC_INDEX, 0x01);
- tpm_read_index(NSC_LDC_INDEX);
+ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0)
goto out_err;
@@ -339,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{0,}
};
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 31831030f73..6e4be3bb2d8 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -94,6 +94,7 @@
#include <linux/idr.h>
#include <linux/wait.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -251,7 +252,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
static DEFINE_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */
+static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */
int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
{
@@ -262,24 +263,35 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
return -EINVAL;
spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (new_ldisc) {
- tty_ldiscs[disc] = *new_ldisc;
- tty_ldiscs[disc].num = disc;
- tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
- tty_ldiscs[disc].refcount = 0;
- } else {
- if(tty_ldiscs[disc].refcount)
- ret = -EBUSY;
- else
- tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
- }
+ tty_ldiscs[disc] = *new_ldisc;
+ tty_ldiscs[disc].num = disc;
+ tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+ tty_ldiscs[disc].refcount = 0;
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
-
EXPORT_SYMBOL(tty_register_ldisc);
+int tty_unregister_ldisc(int disc)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ if (tty_ldiscs[disc].refcount)
+ ret = -EBUSY;
+ else
+ tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(tty_unregister_ldisc);
+
struct tty_ldisc *tty_ldisc_get(int disc)
{
unsigned long flags;
@@ -2169,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
return tty_set_ldisc(tty, ldisc);
}
-static int send_break(struct tty_struct *tty, int duration)
+static int send_break(struct tty_struct *tty, unsigned int duration)
{
tty->driver->break_ctl(tty, -1);
if (!signal_pending(current)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(duration);
+ msleep_interruptible(duration);
}
tty->driver->break_ctl(tty, 0);
if (signal_pending(current))
@@ -2355,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file,
* all by anyone?
*/
if (!arg)
- return send_break(tty, HZ/4);
+ return send_break(tty, 250);
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
- return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+ return send_break(tty, arg ? arg*100 : 250);
case TIOCMGET:
return tty_tiocmget(tty, file, p);
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 06a31da2381..b53e2e2b5ae 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -414,6 +414,16 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
+# ppc64 RTAS watchdog
+config WATCHDOG_RTAS
+ tristate "RTAS watchdog"
+ depends on WATCHDOG && PPC_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 1cd27efa35c..c1838834ea7 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
# Only one watchdog can succeed. We probe the hardware watchdog
# drivers first, then the softdog driver. This means if your hardware
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c
new file mode 100644
index 00000000000..619e2ffca33
--- /dev/null
+++ b/drivers/char/watchdog/wdrtas.c
@@ -0,0 +1,696 @@
+/*
+ * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
+ * RTAS calls are available
+ */
+
+/*
+ * RTAS watchdog driver
+ *
+ * (C) Copyright IBM Corp. 2005
+ * device driver to exploit watchdog RTAS functions
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#include <asm/rtas.h>
+#include <asm/uaccess.h>
+
+#define WDRTAS_MAGIC_CHAR 42
+#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
+ WDIOF_MAGICCLOSE)
+
+MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
+MODULE_DESCRIPTION("RTAS watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int wdrtas_nowayout = 1;
+#else
+static int wdrtas_nowayout = 0;
+#endif
+
+static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
+static char wdrtas_expect_close = 0;
+
+static int wdrtas_interval;
+
+#define WDRTAS_THERMAL_SENSOR 3
+static int wdrtas_token_get_sensor_state;
+#define WDRTAS_SURVEILLANCE_IND 9000
+static int wdrtas_token_set_indicator;
+#define WDRTAS_SP_SPI 28
+static int wdrtas_token_get_sp;
+static int wdrtas_token_event_scan;
+
+#define WDRTAS_DEFAULT_INTERVAL 300
+
+#define WDRTAS_LOGBUFFER_LEN 128
+static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
+
+
+/*** watchdog access functions */
+
+/**
+ * wdrtas_set_interval - sets the watchdog interval
+ * @interval: new interval
+ *
+ * returns 0 on success, <0 on failures
+ *
+ * wdrtas_set_interval sets the watchdog keepalive interval by calling the
+ * RTAS function set-indicator (surveillance). The unit of interval is
+ * seconds.
+ */
+static int
+wdrtas_set_interval(int interval)
+{
+ long result;
+ static int print_msg = 10;
+
+ /* rtas uses minutes */
+ interval = (interval + 59) / 60;
+
+ result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
+ WDRTAS_SURVEILLANCE_IND, 0, interval);
+ if ( (result < 0) && (print_msg) ) {
+ printk(KERN_ERR "wdrtas: setting the watchdog to %i "
+ "timeout failed: %li\n", interval, result);
+ print_msg--;
+ }
+
+ return result;
+}
+
+/**
+ * wdrtas_get_interval - returns the current watchdog interval
+ * @fallback_value: value (in seconds) to use, if the RTAS call fails
+ *
+ * returns the interval
+ *
+ * wdrtas_get_interval returns the current watchdog keepalive interval
+ * as reported by the RTAS function ibm,get-system-parameter. The unit
+ * of the return value is seconds.
+ */
+static int
+wdrtas_get_interval(int fallback_value)
+{
+ long result;
+ char value[4];
+
+ result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
+ WDRTAS_SP_SPI, (void *)__pa(&value), 4);
+ if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) ||
+ (result < 0) ) {
+ printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
+ "timeout (%li). Continuing\n", result);
+ return fallback_value;
+ }
+
+ /* rtas uses minutes */
+ return ((int)value[2]) * 60;
+}
+
+/**
+ * wdrtas_timer_start - starts watchdog
+ *
+ * wdrtas_timer_start starts the watchdog by calling the RTAS function
+ * set-interval (surveillance)
+ */
+static void
+wdrtas_timer_start(void)
+{
+ wdrtas_set_interval(wdrtas_interval);
+}
+
+/**
+ * wdrtas_timer_stop - stops watchdog
+ *
+ * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
+ * set-interval (surveillance)
+ */
+static void
+wdrtas_timer_stop(void)
+{
+ wdrtas_set_interval(0);
+}
+
+/**
+ * wdrtas_log_scanned_event - logs an event we received during keepalive
+ *
+ * wdrtas_log_scanned_event prints a message to the log buffer dumping
+ * the results of the last event-scan call
+ */
+static void
+wdrtas_log_scanned_event(void)
+{
+ int i;
+
+ for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
+ printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
+ wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
+ wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
+ wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
+ wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
+ wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
+ wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
+ wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
+ wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
+}
+
+/**
+ * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
+ *
+ * wdrtas_timer_keepalive restarts the watchdog timer by calling the
+ * RTAS function event-scan and repeats these calls as long as there are
+ * events available. All events will be dumped.
+ */
+static void
+wdrtas_timer_keepalive(void)
+{
+ long result;
+
+ do {
+ result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
+ RTAS_EVENT_SCAN_ALL_EVENTS, 0,
+ (void *)__pa(wdrtas_logbuffer),
+ WDRTAS_LOGBUFFER_LEN);
+ if (result < 0)
+ printk(KERN_ERR "wdrtas: event-scan failed: %li\n",
+ result);
+ if (result == 0)
+ wdrtas_log_scanned_event();
+ } while (result == 0);
+}
+
+/**
+ * wdrtas_get_temperature - returns current temperature
+ *
+ * returns temperature or <0 on failures
+ *
+ * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
+ * uses the RTAS call get-sensor-state, token 3 to do so
+ */
+static int
+wdrtas_get_temperature(void)
+{
+ long result;
+ int temperature = 0;
+
+ result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
+ (void *)__pa(&temperature),
+ WDRTAS_THERMAL_SENSOR, 0);
+
+ if (result < 0)
+ printk(KERN_WARNING "wdrtas: reading the thermal sensor "
+ "faild: %li\n", result);
+ else
+ temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
+
+ return temperature;
+}
+
+/**
+ * wdrtas_get_status - returns the status of the watchdog
+ *
+ * returns a bitmask of defines WDIOF_... as defined in
+ * include/linux/watchdog.h
+ */
+static int
+wdrtas_get_status(void)
+{
+ return 0; /* TODO */
+}
+
+/**
+ * wdrtas_get_boot_status - returns the reason for the last boot
+ *
+ * returns a bitmask of defines WDIOF_... as defined in
+ * include/linux/watchdog.h, indicating why the watchdog rebooted the system
+ */
+static int
+wdrtas_get_boot_status(void)
+{
+ return 0; /* TODO */
+}
+
+/*** watchdog API and operations stuff */
+
+/* wdrtas_write - called when watchdog device is written to
+ * @file: file structure
+ * @buf: user buffer with data
+ * @len: amount to data written
+ * @ppos: position in file
+ *
+ * returns the number of successfully processed characters, which is always
+ * the number of bytes passed to this function
+ *
+ * wdrtas_write processes all the data given to it and looks for the magic
+ * character 'V'. This character allows the watchdog device to be closed
+ * properly.
+ */
+static ssize_t
+wdrtas_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ int i;
+ char c;
+
+ if (!len)
+ goto out;
+
+ if (!wdrtas_nowayout) {
+ wdrtas_expect_close = 0;
+ /* look for 'V' */
+ for (i = 0; i < len; i++) {
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ /* allow to close device */
+ if (c == 'V')
+ wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
+ }
+ }
+
+ wdrtas_timer_keepalive();
+
+out:
+ return len;
+}
+
+/**
+ * wdrtas_ioctl - ioctl function for the watchdog device
+ * @inode: inode structure
+ * @file: file structure
+ * @cmd: command for ioctl
+ * @arg: argument pointer
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * wdrtas_ioctl implements the watchdog API ioctls
+ */
+static int
+wdrtas_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *argp = (void *)arg;
+ int i;
+ static struct watchdog_info wdinfo = {
+ .options = WDRTAS_SUPPORTED_MASK,
+ .firmware_version = 0,
+ .identity = "wdrtas"
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
+ return -EFAULT;
+ return 0;
+
+ case WDIOC_GETSTATUS:
+ i = wdrtas_get_status();
+ return put_user(i, argp);
+
+ case WDIOC_GETBOOTSTATUS:
+ i = wdrtas_get_boot_status();
+ return put_user(i, argp);
+
+ case WDIOC_GETTEMP:
+ if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
+ return -EOPNOTSUPP;
+
+ i = wdrtas_get_temperature();
+ return put_user(i, argp);
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(i, argp))
+ return -EFAULT;
+ if (i & WDIOS_DISABLECARD)
+ wdrtas_timer_stop();
+ if (i & WDIOS_ENABLECARD) {
+ wdrtas_timer_keepalive();
+ wdrtas_timer_start();
+ }
+ if (i & WDIOS_TEMPPANIC) {
+ /* not implemented. Done by H8 */
+ }
+ return 0;
+
+ case WDIOC_KEEPALIVE:
+ wdrtas_timer_keepalive();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(i, argp))
+ return -EFAULT;
+
+ if (wdrtas_set_interval(i))
+ return -EINVAL;
+
+ wdrtas_timer_keepalive();
+
+ if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
+ wdrtas_interval = i;
+ else
+ wdrtas_interval = wdrtas_get_interval(i);
+ /* fallthrough */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(wdrtas_interval, argp);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/**
+ * wdrtas_open - open function of watchdog device
+ * @inode: inode structure
+ * @file: file structure
+ *
+ * returns 0 on success, -EBUSY if the file has been opened already, <0 on
+ * other failures
+ *
+ * function called when watchdog device is opened
+ */
+static int
+wdrtas_open(struct inode *inode, struct file *file)
+{
+ /* only open once */
+ if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
+ atomic_dec(&wdrtas_miscdev_open);
+ return -EBUSY;
+ }
+
+ wdrtas_timer_start();
+ wdrtas_timer_keepalive();
+
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * wdrtas_close - close function of watchdog device
+ * @inode: inode structure
+ * @file: file structure
+ *
+ * returns 0 on success
+ *
+ * close function. Always succeeds
+ */
+static int
+wdrtas_close(struct inode *inode, struct file *file)
+{
+ /* only stop watchdog, if this was announced using 'V' before */
+ if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
+ wdrtas_timer_stop();
+ else {
+ printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
+ "not stopped.\n");
+ wdrtas_timer_keepalive();
+ }
+
+ wdrtas_expect_close = 0;
+ atomic_dec(&wdrtas_miscdev_open);
+ return 0;
+}
+
+/**
+ * wdrtas_temp_read - gives back the temperature in fahrenheit
+ * @file: file structure
+ * @buf: user buffer
+ * @count: number of bytes to be read
+ * @ppos: position in file
+ *
+ * returns always 1 or -EFAULT in case of user space copy failures, <0 on
+ * other failures
+ *
+ * wdrtas_temp_read gives the temperature to the users by copying this
+ * value as one byte into the user space buffer. The unit is Fahrenheit...
+ */
+static ssize_t
+wdrtas_temp_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int temperature = 0;
+
+ temperature = wdrtas_get_temperature();
+ if (temperature < 0)
+ return temperature;
+
+ if (copy_to_user(buf, &temperature, 1))
+ return -EFAULT;
+
+ return 1;
+}
+
+/**
+ * wdrtas_temp_open - open function of temperature device
+ * @inode: inode structure
+ * @file: file structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * function called when temperature device is opened
+ */
+static int
+wdrtas_temp_open(struct inode *inode, struct file *file)
+{
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * wdrtas_temp_close - close function of temperature device
+ * @inode: inode structure
+ * @file: file structure
+ *
+ * returns 0 on success
+ *
+ * close function. Always succeeds
+ */
+static int
+wdrtas_temp_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+/**
+ * wdrtas_reboot - reboot notifier function
+ * @nb: notifier block structure
+ * @code: reboot code
+ * @ptr: unused
+ *
+ * returns NOTIFY_DONE
+ *
+ * wdrtas_reboot stops the watchdog in case of a reboot
+ */
+static int
+wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr)
+{
+ if ( (code==SYS_DOWN) || (code==SYS_HALT) )
+ wdrtas_timer_stop();
+
+ return NOTIFY_DONE;
+}
+
+/*** initialization stuff */
+
+static struct file_operations wdrtas_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdrtas_write,
+ .ioctl = wdrtas_ioctl,
+ .open = wdrtas_open,
+ .release = wdrtas_close,
+};
+
+static struct miscdevice wdrtas_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdrtas_fops,
+};
+
+static struct file_operations wdrtas_temp_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = wdrtas_temp_read,
+ .open = wdrtas_temp_open,
+ .release = wdrtas_temp_close,
+};
+
+static struct miscdevice wdrtas_tempdev = {
+ .minor = TEMP_MINOR,
+ .name = "temperature",
+ .fops = &wdrtas_temp_fops,
+};
+
+static struct notifier_block wdrtas_notifier = {
+ .notifier_call = wdrtas_reboot,
+};
+
+/**
+ * wdrtas_get_tokens - reads in RTAS tokens
+ *
+ * returns 0 on succes, <0 on failure
+ *
+ * wdrtas_get_tokens reads in the tokens for the RTAS calls used in
+ * this watchdog driver. It tolerates, if "get-sensor-state" and
+ * "ibm,get-system-parameter" are not available.
+ */
+static int
+wdrtas_get_tokens(void)
+{
+ wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
+ if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
+ printk(KERN_WARNING "wdrtas: couldn't get token for "
+ "get-sensor-state. Trying to continue without "
+ "temperature support.\n");
+ }
+
+ wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
+ if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
+ printk(KERN_WARNING "wdrtas: couldn't get token for "
+ "ibm,get-system-parameter. Trying to continue with "
+ "a default timeout value of %i seconds.\n",
+ WDRTAS_DEFAULT_INTERVAL);
+ }
+
+ wdrtas_token_set_indicator = rtas_token("set-indicator");
+ if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
+ printk(KERN_ERR "wdrtas: couldn't get token for "
+ "set-indicator. Terminating watchdog code.\n");
+ return -EIO;
+ }
+
+ wdrtas_token_event_scan = rtas_token("event-scan");
+ if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
+ printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
+ "Terminating watchdog code.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * wdrtas_unregister_devs - unregisters the misc dev handlers
+ *
+ * wdrtas_register_devs unregisters the watchdog and temperature watchdog
+ * misc devs
+ */
+static void
+wdrtas_unregister_devs(void)
+{
+ misc_deregister(&wdrtas_miscdev);
+ if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
+ misc_deregister(&wdrtas_tempdev);
+}
+
+/**
+ * wdrtas_register_devs - registers the misc dev handlers
+ *
+ * returns 0 on succes, <0 on failure
+ *
+ * wdrtas_register_devs registers the watchdog and temperature watchdog
+ * misc devs
+ */
+static int
+wdrtas_register_devs(void)
+{
+ int result;
+
+ result = misc_register(&wdrtas_miscdev);
+ if (result) {
+ printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
+ "device. Terminating watchdog code.\n");
+ return result;
+ }
+
+ if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
+ result = misc_register(&wdrtas_tempdev);
+ if (result) {
+ printk(KERN_WARNING "wdrtas: couldn't register "
+ "watchdog temperature misc device. Continuing "
+ "without temperature support.\n");
+ wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * wdrtas_init - init function of the watchdog driver
+ *
+ * returns 0 on succes, <0 on failure
+ *
+ * registers the file handlers and the reboot notifier
+ */
+static int __init
+wdrtas_init(void)
+{
+ if (wdrtas_get_tokens())
+ return -ENODEV;
+
+ if (wdrtas_register_devs())
+ return -ENODEV;
+
+ if (register_reboot_notifier(&wdrtas_notifier)) {
+ printk(KERN_ERR "wdrtas: could not register reboot notifier. "
+ "Terminating watchdog code.\n");
+ wdrtas_unregister_devs();
+ return -ENODEV;
+ }
+
+ if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
+ wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
+ else
+ wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
+
+ return 0;
+}
+
+/**
+ * wdrtas_exit - exit function of the watchdog driver
+ *
+ * unregisters the file handlers and the reboot notifier
+ */
+static void __exit
+wdrtas_exit(void)
+{
+ if (!wdrtas_nowayout)
+ wdrtas_timer_stop();
+
+ wdrtas_unregister_devs();
+
+ unregister_reboot_notifier(&wdrtas_notifier);
+}
+
+module_init(wdrtas_init);
+module_exit(wdrtas_exit);