diff options
Diffstat (limited to 'drivers/char')
39 files changed, 1984 insertions, 1271 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7ccf871d3c9d..43d0cb19ef6a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -940,8 +940,8 @@ config RAW_DRIVER | |||
940 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. | 940 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. |
941 | See the raw(8) manpage for more details. | 941 | See the raw(8) manpage for more details. |
942 | 942 | ||
943 | The raw driver is deprecated and may be removed from 2.7 | 943 | The raw driver is deprecated and will be removed soon. |
944 | kernels. Applications should simply open the device (eg /dev/hda1) | 944 | Applications should simply open the device (eg /dev/hda1) |
945 | with the O_DIRECT flag. | 945 | with the O_DIRECT flag. |
946 | 946 | ||
947 | config HPET | 947 | config HPET |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 1dc4259213a6..2a36561eec68 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -861,13 +861,18 @@ static void change_speed(struct async_struct *info, | |||
861 | 861 | ||
862 | static void rs_put_char(struct tty_struct *tty, unsigned char ch) | 862 | static void rs_put_char(struct tty_struct *tty, unsigned char ch) |
863 | { | 863 | { |
864 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 864 | struct async_struct *info; |
865 | unsigned long flags; | 865 | unsigned long flags; |
866 | 866 | ||
867 | if (!tty) | ||
868 | return; | ||
869 | |||
870 | info = tty->driver_data; | ||
871 | |||
867 | if (serial_paranoia_check(info, tty->name, "rs_put_char")) | 872 | if (serial_paranoia_check(info, tty->name, "rs_put_char")) |
868 | return; | 873 | return; |
869 | 874 | ||
870 | if (!tty || !info->xmit.buf) | 875 | if (!info->xmit.buf) |
871 | return; | 876 | return; |
872 | 877 | ||
873 | local_irq_save(flags); | 878 | local_irq_save(flags); |
@@ -910,13 +915,18 @@ static void rs_flush_chars(struct tty_struct *tty) | |||
910 | static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) | 915 | static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) |
911 | { | 916 | { |
912 | int c, ret = 0; | 917 | int c, ret = 0; |
913 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 918 | struct async_struct *info; |
914 | unsigned long flags; | 919 | unsigned long flags; |
915 | 920 | ||
921 | if (!tty) | ||
922 | return 0; | ||
923 | |||
924 | info = tty->driver_data; | ||
925 | |||
916 | if (serial_paranoia_check(info, tty->name, "rs_write")) | 926 | if (serial_paranoia_check(info, tty->name, "rs_write")) |
917 | return 0; | 927 | return 0; |
918 | 928 | ||
919 | if (!tty || !info->xmit.buf || !tmp_buf) | 929 | if (!info->xmit.buf || !tmp_buf) |
920 | return 0; | 930 | return 0; |
921 | 931 | ||
922 | local_save_flags(flags); | 932 | local_save_flags(flags); |
@@ -1963,10 +1973,6 @@ static _INLINE_ void show_serial_version(void) | |||
1963 | } | 1973 | } |
1964 | 1974 | ||
1965 | 1975 | ||
1966 | int register_serial(struct serial_struct *req); | ||
1967 | void unregister_serial(int line); | ||
1968 | |||
1969 | |||
1970 | static struct tty_operations serial_ops = { | 1976 | static struct tty_operations serial_ops = { |
1971 | .open = rs_open, | 1977 | .open = rs_open, |
1972 | .close = rs_close, | 1978 | .close = rs_close, |
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 6bf2e27dc23a..11f9ee581124 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_ | |||
599 | 599 | ||
600 | #ifdef DEBUG | 600 | #ifdef DEBUG |
601 | if (loopcount++ > 2) { | 601 | if (loopcount++ > 2) { |
602 | printk("Looping in ac_read. loopcount %d\n", loopcount); | 602 | printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); |
603 | } | 603 | } |
604 | #endif | 604 | #endif |
605 | } | 605 | } |
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 7def6ad51798..62cda25724e3 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) | |||
163 | netwinder_ds1620_reset(); | 163 | netwinder_ds1620_reset(); |
164 | netwinder_unlock(&flags); | 164 | netwinder_unlock(&flags); |
165 | 165 | ||
166 | set_current_state(TASK_INTERRUPTIBLE); | 166 | msleep(20); |
167 | schedule_timeout(2); | ||
168 | } | 167 | } |
169 | 168 | ||
170 | static unsigned int ds1620_in(int cmd, int bits) | 169 | 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 220a227e6061..65ffc0be3df9 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"); | |||
1176 | } | 1176 | } |
1177 | #else /* !MODULE */ | 1177 | #else /* !MODULE */ |
1178 | /* print a short no-nonsense boot message */ | 1178 | /* print a short no-nonsense boot message */ |
1179 | printk("zftape compressor v1.00a 970514\n"); | 1179 | printk(KERN_INFO "zftape compressor v1.00a 970514\n"); |
1180 | printk("For use with " FTAPE_VERSION "\n"); | 1180 | printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); |
1181 | #endif /* MODULE */ | 1181 | #endif /* MODULE */ |
1182 | TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); | 1182 | TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); |
1183 | TRACE(ft_t_info, "installing compressor for zftape ..."); | 1183 | TRACE(ft_t_info, "installing compressor for zftape ..."); |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5ec732e6ca92..762fa430fb5b 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp) | |||
834 | printk("\n"); | 834 | printk("\n"); |
835 | 835 | ||
836 | ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ | 836 | ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ |
837 | do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */ | 837 | ns /= 1000000; /* convert to nanoseconds, 10^-9 */ |
838 | printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", | 838 | printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", |
839 | hpetp->hp_which, ns, hpetp->hp_ntimer, | 839 | hpetp->hp_which, ns, hpetp->hp_ntimer, |
840 | cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); | 840 | cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); |
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index a81197640283..6c4b3f986d0c 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c | |||
@@ -20,13 +20,14 @@ | |||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/proc_fs.h> | 22 | #include <linux/proc_fs.h> |
23 | #include <linux/apm_bios.h> | 23 | #include <linux/seq_file.h> |
24 | #include <linux/dmi.h> | ||
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | 27 | ||
27 | #include <linux/i8k.h> | 28 | #include <linux/i8k.h> |
28 | 29 | ||
29 | #define I8K_VERSION "1.13 14/05/2002" | 30 | #define I8K_VERSION "1.14 21/02/2005" |
30 | 31 | ||
31 | #define I8K_SMM_FN_STATUS 0x0025 | 32 | #define I8K_SMM_FN_STATUS 0x0025 |
32 | #define I8K_SMM_POWER_STATUS 0x0069 | 33 | #define I8K_SMM_POWER_STATUS 0x0069 |
@@ -34,7 +35,8 @@ | |||
34 | #define I8K_SMM_GET_FAN 0x00a3 | 35 | #define I8K_SMM_GET_FAN 0x00a3 |
35 | #define I8K_SMM_GET_SPEED 0x02a3 | 36 | #define I8K_SMM_GET_SPEED 0x02a3 |
36 | #define I8K_SMM_GET_TEMP 0x10a3 | 37 | #define I8K_SMM_GET_TEMP 0x10a3 |
37 | #define I8K_SMM_GET_DELL_SIG 0xffa3 | 38 | #define I8K_SMM_GET_DELL_SIG1 0xfea3 |
39 | #define I8K_SMM_GET_DELL_SIG2 0xffa3 | ||
38 | #define I8K_SMM_BIOS_VERSION 0x00a6 | 40 | #define I8K_SMM_BIOS_VERSION 0x00a6 |
39 | 41 | ||
40 | #define I8K_FAN_MULT 30 | 42 | #define I8K_FAN_MULT 30 |
@@ -52,18 +54,7 @@ | |||
52 | 54 | ||
53 | #define I8K_TEMPERATURE_BUG 1 | 55 | #define I8K_TEMPERATURE_BUG 1 |
54 | 56 | ||
55 | #define DELL_SIGNATURE "Dell Computer" | 57 | static char bios_version[4]; |
56 | |||
57 | static char *supported_models[] = { | ||
58 | "Inspiron", | ||
59 | "Latitude", | ||
60 | NULL | ||
61 | }; | ||
62 | |||
63 | static char system_vendor[48] = "?"; | ||
64 | static char product_name [48] = "?"; | ||
65 | static char bios_version [4] = "?"; | ||
66 | static char serial_number[16] = "?"; | ||
67 | 58 | ||
68 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); | 59 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); |
69 | MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); | 60 | MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); |
@@ -73,6 +64,10 @@ static int force; | |||
73 | module_param(force, bool, 0); | 64 | module_param(force, bool, 0); |
74 | MODULE_PARM_DESC(force, "Force loading without checking for supported models"); | 65 | MODULE_PARM_DESC(force, "Force loading without checking for supported models"); |
75 | 66 | ||
67 | static int ignore_dmi; | ||
68 | module_param(ignore_dmi, bool, 0); | ||
69 | MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); | ||
70 | |||
76 | static int restricted; | 71 | static int restricted; |
77 | module_param(restricted, bool, 0); | 72 | module_param(restricted, bool, 0); |
78 | MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); | 73 | MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); |
@@ -81,69 +76,69 @@ static int power_status; | |||
81 | module_param(power_status, bool, 0600); | 76 | module_param(power_status, bool, 0600); |
82 | MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); | 77 | MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); |
83 | 78 | ||
84 | static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *); | 79 | static int i8k_open_fs(struct inode *inode, struct file *file); |
85 | static int i8k_ioctl(struct inode *, struct file *, unsigned int, | 80 | static int i8k_ioctl(struct inode *, struct file *, unsigned int, |
86 | unsigned long); | 81 | unsigned long); |
87 | 82 | ||
88 | static struct file_operations i8k_fops = { | 83 | static struct file_operations i8k_fops = { |
89 | .read = i8k_read, | 84 | .open = i8k_open_fs, |
90 | .ioctl = i8k_ioctl, | 85 | .read = seq_read, |
86 | .llseek = seq_lseek, | ||
87 | .release = single_release, | ||
88 | .ioctl = i8k_ioctl, | ||
89 | }; | ||
90 | |||
91 | struct smm_regs { | ||
92 | unsigned int eax; | ||
93 | unsigned int ebx __attribute__ ((packed)); | ||
94 | unsigned int ecx __attribute__ ((packed)); | ||
95 | unsigned int edx __attribute__ ((packed)); | ||
96 | unsigned int esi __attribute__ ((packed)); | ||
97 | unsigned int edi __attribute__ ((packed)); | ||
91 | }; | 98 | }; |
92 | 99 | ||
93 | typedef struct { | 100 | static inline char *i8k_get_dmi_data(int field) |
94 | unsigned int eax; | 101 | { |
95 | unsigned int ebx __attribute__ ((packed)); | 102 | return dmi_get_system_info(field) ? : "N/A"; |
96 | unsigned int ecx __attribute__ ((packed)); | 103 | } |
97 | unsigned int edx __attribute__ ((packed)); | ||
98 | unsigned int esi __attribute__ ((packed)); | ||
99 | unsigned int edi __attribute__ ((packed)); | ||
100 | } SMMRegisters; | ||
101 | |||
102 | typedef struct { | ||
103 | u8 type; | ||
104 | u8 length; | ||
105 | u16 handle; | ||
106 | } DMIHeader; | ||
107 | 104 | ||
108 | /* | 105 | /* |
109 | * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. | 106 | * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. |
110 | */ | 107 | */ |
111 | static int i8k_smm(SMMRegisters *regs) | 108 | static int i8k_smm(struct smm_regs *regs) |
112 | { | 109 | { |
113 | int rc; | 110 | int rc; |
114 | int eax = regs->eax; | 111 | int eax = regs->eax; |
115 | 112 | ||
116 | asm("pushl %%eax\n\t" \ | 113 | asm("pushl %%eax\n\t" |
117 | "movl 0(%%eax),%%edx\n\t" \ | 114 | "movl 0(%%eax),%%edx\n\t" |
118 | "push %%edx\n\t" \ | 115 | "push %%edx\n\t" |
119 | "movl 4(%%eax),%%ebx\n\t" \ | 116 | "movl 4(%%eax),%%ebx\n\t" |
120 | "movl 8(%%eax),%%ecx\n\t" \ | 117 | "movl 8(%%eax),%%ecx\n\t" |
121 | "movl 12(%%eax),%%edx\n\t" \ | 118 | "movl 12(%%eax),%%edx\n\t" |
122 | "movl 16(%%eax),%%esi\n\t" \ | 119 | "movl 16(%%eax),%%esi\n\t" |
123 | "movl 20(%%eax),%%edi\n\t" \ | 120 | "movl 20(%%eax),%%edi\n\t" |
124 | "popl %%eax\n\t" \ | 121 | "popl %%eax\n\t" |
125 | "out %%al,$0xb2\n\t" \ | 122 | "out %%al,$0xb2\n\t" |
126 | "out %%al,$0x84\n\t" \ | 123 | "out %%al,$0x84\n\t" |
127 | "xchgl %%eax,(%%esp)\n\t" | 124 | "xchgl %%eax,(%%esp)\n\t" |
128 | "movl %%ebx,4(%%eax)\n\t" \ | 125 | "movl %%ebx,4(%%eax)\n\t" |
129 | "movl %%ecx,8(%%eax)\n\t" \ | 126 | "movl %%ecx,8(%%eax)\n\t" |
130 | "movl %%edx,12(%%eax)\n\t" \ | 127 | "movl %%edx,12(%%eax)\n\t" |
131 | "movl %%esi,16(%%eax)\n\t" \ | 128 | "movl %%esi,16(%%eax)\n\t" |
132 | "movl %%edi,20(%%eax)\n\t" \ | 129 | "movl %%edi,20(%%eax)\n\t" |
133 | "popl %%edx\n\t" \ | 130 | "popl %%edx\n\t" |
134 | "movl %%edx,0(%%eax)\n\t" \ | 131 | "movl %%edx,0(%%eax)\n\t" |
135 | "lahf\n\t" \ | 132 | "lahf\n\t" |
136 | "shrl $8,%%eax\n\t" \ | 133 | "shrl $8,%%eax\n\t" |
137 | "andl $1,%%eax\n" \ | 134 | "andl $1,%%eax\n":"=a"(rc) |
138 | : "=a" (rc) | 135 | : "a"(regs) |
139 | : "a" (regs) | 136 | : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); |
140 | : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); | 137 | |
141 | 138 | if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) | |
142 | if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { | 139 | return -EINVAL; |
143 | return -EINVAL; | 140 | |
144 | } | 141 | return 0; |
145 | |||
146 | return 0; | ||
147 | } | 142 | } |
148 | 143 | ||
149 | /* | 144 | /* |
@@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs) | |||
152 | */ | 147 | */ |
153 | static int i8k_get_bios_version(void) | 148 | static int i8k_get_bios_version(void) |
154 | { | 149 | { |
155 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 150 | struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, }; |
156 | int rc; | ||
157 | |||
158 | regs.eax = I8K_SMM_BIOS_VERSION; | ||
159 | if ((rc=i8k_smm(®s)) < 0) { | ||
160 | return rc; | ||
161 | } | ||
162 | |||
163 | return regs.eax; | ||
164 | } | ||
165 | 151 | ||
166 | /* | 152 | return i8k_smm(®s) ? : regs.eax; |
167 | * Read the machine id. | ||
168 | */ | ||
169 | static int i8k_get_serial_number(unsigned char *buff) | ||
170 | { | ||
171 | strlcpy(buff, serial_number, sizeof(serial_number)); | ||
172 | return 0; | ||
173 | } | 153 | } |
174 | 154 | ||
175 | /* | 155 | /* |
@@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff) | |||
177 | */ | 157 | */ |
178 | static int i8k_get_fn_status(void) | 158 | static int i8k_get_fn_status(void) |
179 | { | 159 | { |
180 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 160 | struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; |
181 | int rc; | 161 | int rc; |
182 | 162 | ||
183 | regs.eax = I8K_SMM_FN_STATUS; | 163 | if ((rc = i8k_smm(®s)) < 0) |
184 | if ((rc=i8k_smm(®s)) < 0) { | 164 | return rc; |
185 | return rc; | 165 | |
186 | } | 166 | switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { |
187 | 167 | case I8K_FN_UP: | |
188 | switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { | 168 | return I8K_VOL_UP; |
189 | case I8K_FN_UP: | 169 | case I8K_FN_DOWN: |
190 | return I8K_VOL_UP; | 170 | return I8K_VOL_DOWN; |
191 | case I8K_FN_DOWN: | 171 | case I8K_FN_MUTE: |
192 | return I8K_VOL_DOWN; | 172 | return I8K_VOL_MUTE; |
193 | case I8K_FN_MUTE: | 173 | default: |
194 | return I8K_VOL_MUTE; | 174 | return 0; |
195 | default: | 175 | } |
196 | return 0; | ||
197 | } | ||
198 | } | 176 | } |
199 | 177 | ||
200 | /* | 178 | /* |
@@ -202,20 +180,13 @@ static int i8k_get_fn_status(void) | |||
202 | */ | 180 | */ |
203 | static int i8k_get_power_status(void) | 181 | static int i8k_get_power_status(void) |
204 | { | 182 | { |
205 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 183 | struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; |
206 | int rc; | 184 | int rc; |
207 | 185 | ||
208 | regs.eax = I8K_SMM_POWER_STATUS; | 186 | if ((rc = i8k_smm(®s)) < 0) |
209 | if ((rc=i8k_smm(®s)) < 0) { | 187 | return rc; |
210 | return rc; | 188 | |
211 | } | 189 | return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; |
212 | |||
213 | switch (regs.eax & 0xff) { | ||
214 | case I8K_POWER_AC: | ||
215 | return I8K_AC; | ||
216 | default: | ||
217 | return I8K_BATTERY; | ||
218 | } | ||
219 | } | 190 | } |
220 | 191 | ||
221 | /* | 192 | /* |
@@ -223,16 +194,10 @@ static int i8k_get_power_status(void) | |||
223 | */ | 194 | */ |
224 | static int i8k_get_fan_status(int fan) | 195 | static int i8k_get_fan_status(int fan) |
225 | { | 196 | { |
226 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 197 | struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; |
227 | int rc; | ||
228 | |||
229 | regs.eax = I8K_SMM_GET_FAN; | ||
230 | regs.ebx = fan & 0xff; | ||
231 | if ((rc=i8k_smm(®s)) < 0) { | ||
232 | return rc; | ||
233 | } | ||
234 | 198 | ||
235 | return (regs.eax & 0xff); | 199 | regs.ebx = fan & 0xff; |
200 | return i8k_smm(®s) ? : regs.eax & 0xff; | ||
236 | } | 201 | } |
237 | 202 | ||
238 | /* | 203 | /* |
@@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan) | |||
240 | */ | 205 | */ |
241 | static int i8k_get_fan_speed(int fan) | 206 | static int i8k_get_fan_speed(int fan) |
242 | { | 207 | { |
243 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 208 | struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; |
244 | int rc; | ||
245 | 209 | ||
246 | regs.eax = I8K_SMM_GET_SPEED; | 210 | regs.ebx = fan & 0xff; |
247 | regs.ebx = fan & 0xff; | 211 | return i8k_smm(®s) ? : (regs.eax & 0xffff) * I8K_FAN_MULT; |
248 | if ((rc=i8k_smm(®s)) < 0) { | ||
249 | return rc; | ||
250 | } | ||
251 | |||
252 | return (regs.eax & 0xffff) * I8K_FAN_MULT; | ||
253 | } | 212 | } |
254 | 213 | ||
255 | /* | 214 | /* |
@@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan) | |||
257 | */ | 216 | */ |
258 | static int i8k_set_fan(int fan, int speed) | 217 | static int i8k_set_fan(int fan, int speed) |
259 | { | 218 | { |
260 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 219 | struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; |
261 | int rc; | ||
262 | |||
263 | speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); | ||
264 | 220 | ||
265 | regs.eax = I8K_SMM_SET_FAN; | 221 | speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); |
266 | regs.ebx = (fan & 0xff) | (speed << 8); | 222 | regs.ebx = (fan & 0xff) | (speed << 8); |
267 | if ((rc=i8k_smm(®s)) < 0) { | ||
268 | return rc; | ||
269 | } | ||
270 | 223 | ||
271 | return (i8k_get_fan_status(fan)); | 224 | return i8k_smm(®s) ? : i8k_get_fan_status(fan); |
272 | } | 225 | } |
273 | 226 | ||
274 | /* | 227 | /* |
275 | * Read the cpu temperature. | 228 | * Read the cpu temperature. |
276 | */ | 229 | */ |
277 | static int i8k_get_cpu_temp(void) | 230 | static int i8k_get_temp(int sensor) |
278 | { | 231 | { |
279 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 232 | struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; |
280 | int rc; | 233 | int rc; |
281 | int temp; | 234 | int temp; |
282 | 235 | ||
283 | #ifdef I8K_TEMPERATURE_BUG | 236 | #ifdef I8K_TEMPERATURE_BUG |
284 | static int prev = 0; | 237 | static int prev; |
285 | #endif | 238 | #endif |
239 | regs.ebx = sensor & 0xff; | ||
240 | if ((rc = i8k_smm(®s)) < 0) | ||
241 | return rc; | ||
286 | 242 | ||
287 | regs.eax = I8K_SMM_GET_TEMP; | 243 | temp = regs.eax & 0xff; |
288 | if ((rc=i8k_smm(®s)) < 0) { | ||
289 | return rc; | ||
290 | } | ||
291 | temp = regs.eax & 0xff; | ||
292 | 244 | ||
293 | #ifdef I8K_TEMPERATURE_BUG | 245 | #ifdef I8K_TEMPERATURE_BUG |
294 | /* | 246 | /* |
295 | * Sometimes the temperature sensor returns 0x99, which is out of range. | 247 | * Sometimes the temperature sensor returns 0x99, which is out of range. |
296 | * In this case we return (once) the previous cached value. For example: | 248 | * In this case we return (once) the previous cached value. For example: |
297 | # 1003655137 00000058 00005a4b | 249 | # 1003655137 00000058 00005a4b |
298 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees | 250 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees |
299 | # 1003655139 00000054 00005c52 | 251 | # 1003655139 00000054 00005c52 |
300 | */ | 252 | */ |
301 | if (temp > I8K_MAX_TEMP) { | 253 | if (temp > I8K_MAX_TEMP) { |
302 | temp = prev; | 254 | temp = prev; |
303 | prev = I8K_MAX_TEMP; | 255 | prev = I8K_MAX_TEMP; |
304 | } else { | 256 | } else { |
305 | prev = temp; | 257 | prev = temp; |
306 | } | 258 | } |
307 | #endif | 259 | #endif |
308 | 260 | ||
309 | return temp; | 261 | return temp; |
310 | } | 262 | } |
311 | 263 | ||
312 | static int i8k_get_dell_signature(void) | 264 | static int i8k_get_dell_signature(int req_fn) |
313 | { | 265 | { |
314 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 266 | struct smm_regs regs = { .eax = req_fn, }; |
315 | int rc; | 267 | int rc; |
316 | 268 | ||
317 | regs.eax = I8K_SMM_GET_DELL_SIG; | 269 | if ((rc = i8k_smm(®s)) < 0) |
318 | if ((rc=i8k_smm(®s)) < 0) { | 270 | return rc; |
319 | return rc; | ||
320 | } | ||
321 | 271 | ||
322 | if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { | 272 | return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; |
323 | return 0; | ||
324 | } else { | ||
325 | return -1; | ||
326 | } | ||
327 | } | 273 | } |
328 | 274 | ||
329 | static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | 275 | static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, |
330 | unsigned long arg) | 276 | unsigned long arg) |
331 | { | 277 | { |
332 | int val; | 278 | int val = 0; |
333 | int speed; | 279 | int speed; |
334 | unsigned char buff[16]; | 280 | unsigned char buff[16]; |
335 | int __user *argp = (int __user *)arg; | 281 | int __user *argp = (int __user *)arg; |
336 | |||
337 | if (!argp) | ||
338 | return -EINVAL; | ||
339 | |||
340 | switch (cmd) { | ||
341 | case I8K_BIOS_VERSION: | ||
342 | val = i8k_get_bios_version(); | ||
343 | break; | ||
344 | |||
345 | case I8K_MACHINE_ID: | ||
346 | memset(buff, 0, 16); | ||
347 | val = i8k_get_serial_number(buff); | ||
348 | break; | ||
349 | |||
350 | case I8K_FN_STATUS: | ||
351 | val = i8k_get_fn_status(); | ||
352 | break; | ||
353 | |||
354 | case I8K_POWER_STATUS: | ||
355 | val = i8k_get_power_status(); | ||
356 | break; | ||
357 | |||
358 | case I8K_GET_TEMP: | ||
359 | val = i8k_get_cpu_temp(); | ||
360 | break; | ||
361 | |||
362 | case I8K_GET_SPEED: | ||
363 | if (copy_from_user(&val, argp, sizeof(int))) { | ||
364 | return -EFAULT; | ||
365 | } | ||
366 | val = i8k_get_fan_speed(val); | ||
367 | break; | ||
368 | |||
369 | case I8K_GET_FAN: | ||
370 | if (copy_from_user(&val, argp, sizeof(int))) { | ||
371 | return -EFAULT; | ||
372 | } | ||
373 | val = i8k_get_fan_status(val); | ||
374 | break; | ||
375 | 282 | ||
376 | case I8K_SET_FAN: | 283 | if (!argp) |
377 | if (restricted && !capable(CAP_SYS_ADMIN)) { | 284 | return -EINVAL; |
378 | return -EPERM; | ||
379 | } | ||
380 | if (copy_from_user(&val, argp, sizeof(int))) { | ||
381 | return -EFAULT; | ||
382 | } | ||
383 | if (copy_from_user(&speed, argp+1, sizeof(int))) { | ||
384 | return -EFAULT; | ||
385 | } | ||
386 | val = i8k_set_fan(val, speed); | ||
387 | break; | ||
388 | 285 | ||
389 | default: | 286 | switch (cmd) { |
390 | return -EINVAL; | 287 | case I8K_BIOS_VERSION: |
391 | } | 288 | val = i8k_get_bios_version(); |
289 | break; | ||
392 | 290 | ||
393 | if (val < 0) { | 291 | case I8K_MACHINE_ID: |
394 | return val; | 292 | memset(buff, 0, 16); |
395 | } | 293 | strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff)); |
294 | break; | ||
396 | 295 | ||
397 | switch (cmd) { | 296 | case I8K_FN_STATUS: |
398 | case I8K_BIOS_VERSION: | 297 | val = i8k_get_fn_status(); |
399 | if (copy_to_user(argp, &val, 4)) { | 298 | break; |
400 | return -EFAULT; | ||
401 | } | ||
402 | break; | ||
403 | case I8K_MACHINE_ID: | ||
404 | if (copy_to_user(argp, buff, 16)) { | ||
405 | return -EFAULT; | ||
406 | } | ||
407 | break; | ||
408 | default: | ||
409 | if (copy_to_user(argp, &val, sizeof(int))) { | ||
410 | return -EFAULT; | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | 299 | ||
415 | return 0; | 300 | case I8K_POWER_STATUS: |
416 | } | 301 | val = i8k_get_power_status(); |
302 | break; | ||
417 | 303 | ||
418 | /* | 304 | case I8K_GET_TEMP: |
419 | * Print the information for /proc/i8k. | 305 | val = i8k_get_temp(0); |
420 | */ | 306 | break; |
421 | static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) | ||
422 | { | ||
423 | int n, fn_key, cpu_temp, ac_power; | ||
424 | int left_fan, right_fan, left_speed, right_speed; | ||
425 | |||
426 | cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ | ||
427 | left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ | ||
428 | right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ | ||
429 | left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ | ||
430 | right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ | ||
431 | fn_key = i8k_get_fn_status(); /* 750 µs */ | ||
432 | if (power_status) { | ||
433 | ac_power = i8k_get_power_status(); /* 14700 µs */ | ||
434 | } else { | ||
435 | ac_power = -1; | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * Info: | ||
440 | * | ||
441 | * 1) Format version (this will change if format changes) | ||
442 | * 2) BIOS version | ||
443 | * 3) BIOS machine ID | ||
444 | * 4) Cpu temperature | ||
445 | * 5) Left fan status | ||
446 | * 6) Right fan status | ||
447 | * 7) Left fan speed | ||
448 | * 8) Right fan speed | ||
449 | * 9) AC power | ||
450 | * 10) Fn Key status | ||
451 | */ | ||
452 | n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", | ||
453 | I8K_PROC_FMT, | ||
454 | bios_version, | ||
455 | serial_number, | ||
456 | cpu_temp, | ||
457 | left_fan, | ||
458 | right_fan, | ||
459 | left_speed, | ||
460 | right_speed, | ||
461 | ac_power, | ||
462 | fn_key); | ||
463 | |||
464 | return n; | ||
465 | } | ||
466 | 307 | ||
467 | static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos) | 308 | case I8K_GET_SPEED: |
468 | { | 309 | if (copy_from_user(&val, argp, sizeof(int))) |
469 | int n; | 310 | return -EFAULT; |
470 | char info[128]; | ||
471 | 311 | ||
472 | n = i8k_get_info(info, NULL, 0, 128); | 312 | val = i8k_get_fan_speed(val); |
473 | if (n <= 0) { | 313 | break; |
474 | return n; | ||
475 | } | ||
476 | 314 | ||
477 | if (*fpos >= n) { | 315 | case I8K_GET_FAN: |
478 | return 0; | 316 | if (copy_from_user(&val, argp, sizeof(int))) |
479 | } | 317 | return -EFAULT; |
480 | 318 | ||
481 | if ((*fpos + len) >= n) { | 319 | val = i8k_get_fan_status(val); |
482 | len = n - *fpos; | 320 | break; |
483 | } | ||
484 | 321 | ||
485 | if (copy_to_user(buffer, info, len) != 0) { | 322 | case I8K_SET_FAN: |
486 | return -EFAULT; | 323 | if (restricted && !capable(CAP_SYS_ADMIN)) |
487 | } | 324 | return -EPERM; |
488 | 325 | ||
489 | *fpos += len; | 326 | if (copy_from_user(&val, argp, sizeof(int))) |
490 | return len; | 327 | return -EFAULT; |
491 | } | ||
492 | 328 | ||
493 | static char* __init string_trim(char *s, int size) | 329 | if (copy_from_user(&speed, argp + 1, sizeof(int))) |
494 | { | 330 | return -EFAULT; |
495 | int len; | ||
496 | char *p; | ||
497 | 331 | ||
498 | if ((len = strlen(s)) > size) { | 332 | val = i8k_set_fan(val, speed); |
499 | len = size; | 333 | break; |
500 | } | ||
501 | 334 | ||
502 | for (p=s+len-1; len && (*p==' '); len--,p--) { | 335 | default: |
503 | *p = '\0'; | 336 | return -EINVAL; |
504 | } | 337 | } |
505 | 338 | ||
506 | return s; | 339 | if (val < 0) |
507 | } | 340 | return val; |
508 | 341 | ||
509 | /* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ | 342 | switch (cmd) { |
343 | case I8K_BIOS_VERSION: | ||
344 | if (copy_to_user(argp, &val, 4)) | ||
345 | return -EFAULT; | ||
510 | 346 | ||
511 | /* | 347 | break; |
512 | * |<-- dmi->length -->| | 348 | case I8K_MACHINE_ID: |
513 | * | | | 349 | if (copy_to_user(argp, buff, 16)) |
514 | * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0 | 350 | return -EFAULT; |
515 | * | | | ||
516 | * +-----------------------+ | ||
517 | */ | ||
518 | static char* __init dmi_string(DMIHeader *dmi, u8 s) | ||
519 | { | ||
520 | u8 *p; | ||
521 | 351 | ||
522 | if (!s) { | 352 | break; |
523 | return ""; | 353 | default: |
524 | } | 354 | if (copy_to_user(argp, &val, sizeof(int))) |
525 | s--; | 355 | return -EFAULT; |
526 | 356 | ||
527 | p = (u8 *)dmi + dmi->length; | 357 | break; |
528 | while (s > 0) { | 358 | } |
529 | p += strlen(p); | ||
530 | p++; | ||
531 | s--; | ||
532 | } | ||
533 | 359 | ||
534 | return p; | 360 | return 0; |
535 | } | 361 | } |
536 | 362 | ||
537 | static void __init dmi_decode(DMIHeader *dmi) | 363 | /* |
364 | * Print the information for /proc/i8k. | ||
365 | */ | ||
366 | static int i8k_proc_show(struct seq_file *seq, void *offset) | ||
538 | { | 367 | { |
539 | u8 *data = (u8 *) dmi; | 368 | int fn_key, cpu_temp, ac_power; |
540 | char *p; | 369 | int left_fan, right_fan, left_speed, right_speed; |
541 | 370 | ||
542 | #ifdef I8K_DEBUG | 371 | cpu_temp = i8k_get_temp(0); /* 11100 µs */ |
543 | int i; | 372 | left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ |
544 | printk("%08x ", (int)data); | 373 | right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ |
545 | for (i=0; i<data[1] && i<64; i++) { | 374 | left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ |
546 | printk("%02x ", data[i]); | 375 | right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ |
547 | } | 376 | fn_key = i8k_get_fn_status(); /* 750 µs */ |
548 | printk("\n"); | 377 | if (power_status) |
549 | #endif | 378 | ac_power = i8k_get_power_status(); /* 14700 µs */ |
550 | 379 | else | |
551 | switch (dmi->type) { | 380 | ac_power = -1; |
552 | case 0: /* BIOS Information */ | ||
553 | p = dmi_string(dmi,data[5]); | ||
554 | if (*p) { | ||
555 | strlcpy(bios_version, p, sizeof(bios_version)); | ||
556 | string_trim(bios_version, sizeof(bios_version)); | ||
557 | } | ||
558 | break; | ||
559 | case 1: /* System Information */ | ||
560 | p = dmi_string(dmi,data[4]); | ||
561 | if (*p) { | ||
562 | strlcpy(system_vendor, p, sizeof(system_vendor)); | ||
563 | string_trim(system_vendor, sizeof(system_vendor)); | ||
564 | } | ||
565 | p = dmi_string(dmi,data[5]); | ||
566 | if (*p) { | ||
567 | strlcpy(product_name, p, sizeof(product_name)); | ||
568 | string_trim(product_name, sizeof(product_name)); | ||
569 | } | ||
570 | p = dmi_string(dmi,data[7]); | ||
571 | if (*p) { | ||
572 | strlcpy(serial_number, p, sizeof(serial_number)); | ||
573 | string_trim(serial_number, sizeof(serial_number)); | ||
574 | } | ||
575 | break; | ||
576 | } | ||
577 | } | ||
578 | 381 | ||
579 | static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) | ||
580 | { | ||
581 | u8 *buf; | ||
582 | u8 *data; | ||
583 | DMIHeader *dmi; | ||
584 | int i = 1; | ||
585 | |||
586 | buf = ioremap(base, len); | ||
587 | if (buf == NULL) { | ||
588 | return -1; | ||
589 | } | ||
590 | data = buf; | ||
591 | |||
592 | /* | ||
593 | * Stop when we see al the items the table claimed to have | ||
594 | * or we run off the end of the table (also happens) | ||
595 | */ | ||
596 | while ((i<num) && ((data-buf) < len)) { | ||
597 | dmi = (DMIHeader *)data; | ||
598 | /* | ||
599 | * Avoid misparsing crud if the length of the last | ||
600 | * record is crap | ||
601 | */ | ||
602 | if ((data-buf+dmi->length) >= len) { | ||
603 | break; | ||
604 | } | ||
605 | fn(dmi); | ||
606 | data += dmi->length; | ||
607 | /* | 382 | /* |
608 | * Don't go off the end of the data if there is | 383 | * Info: |
609 | * stuff looking like string fill past the end | 384 | * |
385 | * 1) Format version (this will change if format changes) | ||
386 | * 2) BIOS version | ||
387 | * 3) BIOS machine ID | ||
388 | * 4) Cpu temperature | ||
389 | * 5) Left fan status | ||
390 | * 6) Right fan status | ||
391 | * 7) Left fan speed | ||
392 | * 8) Right fan speed | ||
393 | * 9) AC power | ||
394 | * 10) Fn Key status | ||
610 | */ | 395 | */ |
611 | while (((data-buf) < len) && (*data || data[1])) { | 396 | return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", |
612 | data++; | 397 | I8K_PROC_FMT, |
613 | } | 398 | bios_version, |
614 | data += 2; | 399 | dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A", |
615 | i++; | 400 | cpu_temp, |
616 | } | 401 | left_fan, right_fan, left_speed, right_speed, |
617 | iounmap(buf); | 402 | ac_power, fn_key); |
618 | |||
619 | return 0; | ||
620 | } | 403 | } |
621 | 404 | ||
622 | static int __init dmi_iterate(void (*decode)(DMIHeader *)) | 405 | static int i8k_open_fs(struct inode *inode, struct file *file) |
623 | { | 406 | { |
624 | unsigned char buf[20]; | 407 | return single_open(file, i8k_proc_show, NULL); |
625 | void __iomem *p = ioremap(0xe0000, 0x20000), *q; | ||
626 | |||
627 | if (!p) | ||
628 | return -1; | ||
629 | |||
630 | for (q = p; q < p + 0x20000; q += 16) { | ||
631 | memcpy_fromio(buf, q, 20); | ||
632 | if (memcmp(buf, "_DMI_", 5)==0) { | ||
633 | u16 num = buf[13]<<8 | buf[12]; | ||
634 | u16 len = buf [7]<<8 | buf [6]; | ||
635 | u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; | ||
636 | #ifdef I8K_DEBUG | ||
637 | printk(KERN_INFO "DMI %d.%d present.\n", | ||
638 | buf[14]>>4, buf[14]&0x0F); | ||
639 | printk(KERN_INFO "%d structures occupying %d bytes.\n", | ||
640 | buf[13]<<8 | buf[12], | ||
641 | buf [7]<<8 | buf[6]); | ||
642 | printk(KERN_INFO "DMI table at 0x%08X.\n", | ||
643 | buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]); | ||
644 | #endif | ||
645 | if (dmi_table(base, len, num, decode)==0) { | ||
646 | iounmap(p); | ||
647 | return 0; | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | iounmap(p); | ||
652 | return -1; | ||
653 | } | 408 | } |
654 | /* end of DMI code */ | ||
655 | |||
656 | /* | ||
657 | * Get DMI information. | ||
658 | */ | ||
659 | static int __init i8k_dmi_probe(void) | ||
660 | { | ||
661 | char **p; | ||
662 | |||
663 | if (dmi_iterate(dmi_decode) != 0) { | ||
664 | printk(KERN_INFO "i8k: unable to get DMI information\n"); | ||
665 | return -ENODEV; | ||
666 | } | ||
667 | |||
668 | if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) { | ||
669 | printk(KERN_INFO "i8k: not running on a Dell system\n"); | ||
670 | return -ENODEV; | ||
671 | } | ||
672 | |||
673 | for (p=supported_models; ; p++) { | ||
674 | if (!*p) { | ||
675 | printk(KERN_INFO "i8k: unsupported model: %s\n", product_name); | ||
676 | return -ENODEV; | ||
677 | } | ||
678 | if (strncmp(product_name,*p,strlen(*p)) == 0) { | ||
679 | break; | ||
680 | } | ||
681 | } | ||
682 | 409 | ||
683 | return 0; | 410 | static struct dmi_system_id __initdata i8k_dmi_table[] = { |
684 | } | 411 | { |
412 | .ident = "Dell Inspiron", | ||
413 | .matches = { | ||
414 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), | ||
415 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), | ||
416 | }, | ||
417 | }, | ||
418 | { | ||
419 | .ident = "Dell Latitude", | ||
420 | .matches = { | ||
421 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), | ||
422 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), | ||
423 | }, | ||
424 | }, | ||
425 | { | ||
426 | .ident = "Dell Inspiron 2", | ||
427 | .matches = { | ||
428 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
429 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), | ||
430 | }, | ||
431 | }, | ||
432 | { | ||
433 | .ident = "Dell Latitude 2", | ||
434 | .matches = { | ||
435 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
436 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), | ||
437 | }, | ||
438 | }, | ||
439 | { } | ||
440 | }; | ||
685 | 441 | ||
686 | /* | 442 | /* |
687 | * Probe for the presence of a supported laptop. | 443 | * Probe for the presence of a supported laptop. |
688 | */ | 444 | */ |
689 | static int __init i8k_probe(void) | 445 | static int __init i8k_probe(void) |
690 | { | 446 | { |
691 | char buff[4]; | 447 | char buff[4]; |
692 | int version; | 448 | int version; |
693 | int smm_found = 0; | 449 | |
694 | |||
695 | /* | ||
696 | * Get DMI information | ||
697 | */ | ||
698 | if (i8k_dmi_probe() != 0) { | ||
699 | printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", | ||
700 | system_vendor, product_name, bios_version); | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * Get SMM Dell signature | ||
705 | */ | ||
706 | if (i8k_get_dell_signature() != 0) { | ||
707 | printk(KERN_INFO "i8k: unable to get SMM Dell signature\n"); | ||
708 | } else { | ||
709 | smm_found = 1; | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * Get SMM BIOS version. | ||
714 | */ | ||
715 | version = i8k_get_bios_version(); | ||
716 | if (version <= 0) { | ||
717 | printk(KERN_INFO "i8k: unable to get SMM BIOS version\n"); | ||
718 | } else { | ||
719 | smm_found = 1; | ||
720 | buff[0] = (version >> 16) & 0xff; | ||
721 | buff[1] = (version >> 8) & 0xff; | ||
722 | buff[2] = (version) & 0xff; | ||
723 | buff[3] = '\0'; | ||
724 | /* | 450 | /* |
725 | * If DMI BIOS version is unknown use SMM BIOS version. | 451 | * Get DMI information |
726 | */ | 452 | */ |
727 | if (bios_version[0] == '?') { | 453 | if (!dmi_check_system(i8k_dmi_table)) { |
728 | strcpy(bios_version, buff); | 454 | if (!ignore_dmi && !force) |
455 | return -ENODEV; | ||
456 | |||
457 | printk(KERN_INFO "i8k: not running on a supported Dell system.\n"); | ||
458 | printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", | ||
459 | i8k_get_dmi_data(DMI_SYS_VENDOR), | ||
460 | i8k_get_dmi_data(DMI_PRODUCT_NAME), | ||
461 | i8k_get_dmi_data(DMI_BIOS_VERSION)); | ||
729 | } | 462 | } |
463 | |||
464 | strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version)); | ||
465 | |||
730 | /* | 466 | /* |
731 | * Check if the two versions match. | 467 | * Get SMM Dell signature |
732 | */ | 468 | */ |
733 | if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) { | 469 | if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && |
734 | printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n", | 470 | i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { |
735 | buff, bios_version); | 471 | printk(KERN_ERR "i8k: unable to get SMM Dell signature\n"); |
472 | if (!force) | ||
473 | return -ENODEV; | ||
736 | } | 474 | } |
737 | } | ||
738 | 475 | ||
739 | if (!smm_found && !force) { | 476 | /* |
740 | return -ENODEV; | 477 | * Get SMM BIOS version. |
741 | } | 478 | */ |
479 | version = i8k_get_bios_version(); | ||
480 | if (version <= 0) { | ||
481 | printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n"); | ||
482 | } else { | ||
483 | buff[0] = (version >> 16) & 0xff; | ||
484 | buff[1] = (version >> 8) & 0xff; | ||
485 | buff[2] = (version) & 0xff; | ||
486 | buff[3] = '\0'; | ||
487 | /* | ||
488 | * If DMI BIOS version is unknown use SMM BIOS version. | ||
489 | */ | ||
490 | if (!dmi_get_system_info(DMI_BIOS_VERSION)) | ||
491 | strlcpy(bios_version, buff, sizeof(bios_version)); | ||
492 | |||
493 | /* | ||
494 | * Check if the two versions match. | ||
495 | */ | ||
496 | if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) | ||
497 | printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n", | ||
498 | buff, bios_version); | ||
499 | } | ||
742 | 500 | ||
743 | return 0; | 501 | return 0; |
744 | } | 502 | } |
745 | 503 | ||
746 | #ifdef MODULE | 504 | static int __init i8k_init(void) |
747 | static | ||
748 | #endif | ||
749 | int __init i8k_init(void) | ||
750 | { | 505 | { |
751 | struct proc_dir_entry *proc_i8k; | 506 | struct proc_dir_entry *proc_i8k; |
752 | |||
753 | /* Are we running on an supported laptop? */ | ||
754 | if (i8k_probe() != 0) { | ||
755 | return -ENODEV; | ||
756 | } | ||
757 | |||
758 | /* Register the proc entry */ | ||
759 | proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info); | ||
760 | if (!proc_i8k) { | ||
761 | return -ENOENT; | ||
762 | } | ||
763 | proc_i8k->proc_fops = &i8k_fops; | ||
764 | proc_i8k->owner = THIS_MODULE; | ||
765 | |||
766 | printk(KERN_INFO | ||
767 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", | ||
768 | I8K_VERSION); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | 507 | ||
773 | #ifdef MODULE | 508 | /* Are we running on an supported laptop? */ |
774 | int init_module(void) | 509 | if (i8k_probe()) |
775 | { | 510 | return -ENODEV; |
776 | return i8k_init(); | 511 | |
512 | /* Register the proc entry */ | ||
513 | proc_i8k = create_proc_entry("i8k", 0, NULL); | ||
514 | if (!proc_i8k) | ||
515 | return -ENOENT; | ||
516 | |||
517 | proc_i8k->proc_fops = &i8k_fops; | ||
518 | proc_i8k->owner = THIS_MODULE; | ||
519 | |||
520 | printk(KERN_INFO | ||
521 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", | ||
522 | I8K_VERSION); | ||
523 | |||
524 | return 0; | ||
777 | } | 525 | } |
778 | 526 | ||
779 | void cleanup_module(void) | 527 | static void __exit i8k_exit(void) |
780 | { | 528 | { |
781 | /* Remove the proc entry */ | 529 | remove_proc_entry("i8k", NULL); |
782 | remove_proc_entry("i8k", NULL); | ||
783 | |||
784 | printk(KERN_INFO "i8k: module unloaded\n"); | ||
785 | } | 530 | } |
786 | #endif | ||
787 | 531 | ||
788 | /* end of file */ | 532 | module_init(i8k_init); |
533 | module_exit(i8k_exit); | ||
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c index fd299d6c42ac..cb8f4198e9a3 100644 --- a/drivers/char/ip2/i2cmd.c +++ b/drivers/char/ip2/i2cmd.c | |||
@@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME | |||
97 | //static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING | 97 | //static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING |
98 | //static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB | 98 | //static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB |
99 | //static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB | 99 | //static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB |
100 | static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS | 100 | //static UCHAR ct47[]={ 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS |
101 | //static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB | 101 | //static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB |
102 | //static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB | 102 | //static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB |
103 | //static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB | 103 | //static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB |
@@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW | |||
162 | // This routine sets the parameters of command 47 and returns a pointer to the | 162 | // This routine sets the parameters of command 47 and returns a pointer to the |
163 | // appropriate structure. | 163 | // appropriate structure. |
164 | //****************************************************************************** | 164 | //****************************************************************************** |
165 | #if 0 | ||
165 | cmdSyntaxPtr | 166 | cmdSyntaxPtr |
166 | i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) | 167 | i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) |
167 | { | 168 | { |
@@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) | |||
175 | pCM->cmd[6] = (unsigned char) (lflag >> 8); | 176 | pCM->cmd[6] = (unsigned char) (lflag >> 8); |
176 | return pCM; | 177 | return pCM; |
177 | } | 178 | } |
179 | #endif /* 0 */ | ||
178 | 180 | ||
179 | //****************************************************************************** | 181 | //****************************************************************************** |
180 | // Function: i2cmdBaudDef(which, rate) | 182 | // Function: i2cmdBaudDef(which, rate) |
@@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) | |||
187 | // This routine sets the parameters of commands 54 or 55 (according to the | 189 | // This routine sets the parameters of commands 54 or 55 (according to the |
188 | // argument which), and returns a pointer to the appropriate structure. | 190 | // argument which), and returns a pointer to the appropriate structure. |
189 | //****************************************************************************** | 191 | //****************************************************************************** |
190 | cmdSyntaxPtr | 192 | static cmdSyntaxPtr |
191 | i2cmdBaudDef(int which, unsigned short rate) | 193 | i2cmdBaudDef(int which, unsigned short rate) |
192 | { | 194 | { |
193 | cmdSyntaxPtr pCM; | 195 | cmdSyntaxPtr pCM; |
diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index c41728a85710..baa4e721b758 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h | |||
@@ -64,16 +64,6 @@ typedef struct _cmdSyntax | |||
64 | // directly from user-level | 64 | // directly from user-level |
65 | #define VAR 0x10 // This command is of variable length! | 65 | #define VAR 0x10 // This command is of variable length! |
66 | 66 | ||
67 | //----------------------------------- | ||
68 | // External declarations for i2cmd.c | ||
69 | //----------------------------------- | ||
70 | // Routine to set up parameters for the "define hot-key sequence" command. Since | ||
71 | // there is more than one parameter to assign, we must use a function rather | ||
72 | // than a macro (used usually). | ||
73 | // | ||
74 | extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag); | ||
75 | extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate); | ||
76 | |||
77 | // Declarations for the global arrays used to bear the commands and their | 67 | // Declarations for the global arrays used to bear the commands and their |
78 | // arguments. | 68 | // arguments. |
79 | // | 69 | // |
@@ -433,6 +423,7 @@ static UCHAR cc02[]; | |||
433 | #define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking | 423 | #define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking |
434 | #define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking | 424 | #define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking |
435 | 425 | ||
426 | #if 0 | ||
436 | // COMMAND 47: Send Protocol info via Unix flags: | 427 | // COMMAND 47: Send Protocol info via Unix flags: |
437 | // iflag = Unix tty t_iflag | 428 | // iflag = Unix tty t_iflag |
438 | // cflag = Unix tty t_cflag | 429 | // cflag = Unix tty t_cflag |
@@ -441,6 +432,7 @@ static UCHAR cc02[]; | |||
441 | // within these flags | 432 | // within these flags |
442 | // | 433 | // |
443 | #define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag) | 434 | #define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag) |
435 | #endif /* 0 */ | ||
444 | 436 | ||
445 | #define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl | 437 | #define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl |
446 | #define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl | 438 | #define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl |
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 3b8314b4249a..cf0cd58d6305 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c | |||
@@ -2691,16 +2691,6 @@ no_xon: | |||
2691 | pCh->flags |= ASYNC_CHECK_CD; | 2691 | pCh->flags |= ASYNC_CHECK_CD; |
2692 | } | 2692 | } |
2693 | 2693 | ||
2694 | #ifdef XXX | ||
2695 | do_flags_thing: // This is a test, we don't do the flags thing | ||
2696 | |||
2697 | if ( (cflag & CRTSCTS) ) { | ||
2698 | cflag |= 014000000000; | ||
2699 | } | ||
2700 | i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, | ||
2701 | CMD_UNIX_FLAGS(iflag,cflag,lflag)); | ||
2702 | #endif | ||
2703 | |||
2704 | service_it: | 2694 | service_it: |
2705 | i2DrainOutput( pCh, 100 ); | 2695 | i2DrainOutput( pCh, 100 ); |
2706 | } | 2696 | } |
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 88d1ad656e99..e0a53570fea1 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/semaphore.h> | 45 | #include <asm/semaphore.h> |
46 | #include <linux/init.h> | 46 | #include <linux/init.h> |
47 | #include <linux/device.h> | 47 | #include <linux/device.h> |
48 | #include <linux/compat.h> | ||
48 | 49 | ||
49 | #define IPMI_DEVINTF_VERSION "v33" | 50 | #define IPMI_DEVINTF_VERSION "v33" |
50 | 51 | ||
@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode, | |||
500 | return rv; | 501 | return rv; |
501 | } | 502 | } |
502 | 503 | ||
504 | #ifdef CONFIG_COMPAT | ||
505 | |||
506 | /* | ||
507 | * The following code contains code for supporting 32-bit compatible | ||
508 | * ioctls on 64-bit kernels. This allows running 32-bit apps on the | ||
509 | * 64-bit kernel | ||
510 | */ | ||
511 | #define COMPAT_IPMICTL_SEND_COMMAND \ | ||
512 | _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req) | ||
513 | #define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \ | ||
514 | _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime) | ||
515 | #define COMPAT_IPMICTL_RECEIVE_MSG \ | ||
516 | _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv) | ||
517 | #define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \ | ||
518 | _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv) | ||
519 | |||
520 | struct compat_ipmi_msg { | ||
521 | u8 netfn; | ||
522 | u8 cmd; | ||
523 | u16 data_len; | ||
524 | compat_uptr_t data; | ||
525 | }; | ||
526 | |||
527 | struct compat_ipmi_req { | ||
528 | compat_uptr_t addr; | ||
529 | compat_uint_t addr_len; | ||
530 | compat_long_t msgid; | ||
531 | struct compat_ipmi_msg msg; | ||
532 | }; | ||
533 | |||
534 | struct compat_ipmi_recv { | ||
535 | compat_int_t recv_type; | ||
536 | compat_uptr_t addr; | ||
537 | compat_uint_t addr_len; | ||
538 | compat_long_t msgid; | ||
539 | struct compat_ipmi_msg msg; | ||
540 | }; | ||
541 | |||
542 | struct compat_ipmi_req_settime { | ||
543 | struct compat_ipmi_req req; | ||
544 | compat_int_t retries; | ||
545 | compat_uint_t retry_time_ms; | ||
546 | }; | ||
547 | |||
548 | /* | ||
549 | * Define some helper functions for copying IPMI data | ||
550 | */ | ||
551 | static long get_compat_ipmi_msg(struct ipmi_msg *p64, | ||
552 | struct compat_ipmi_msg __user *p32) | ||
553 | { | ||
554 | compat_uptr_t tmp; | ||
555 | |||
556 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
557 | __get_user(p64->netfn, &p32->netfn) || | ||
558 | __get_user(p64->cmd, &p32->cmd) || | ||
559 | __get_user(p64->data_len, &p32->data_len) || | ||
560 | __get_user(tmp, &p32->data)) | ||
561 | return -EFAULT; | ||
562 | p64->data = compat_ptr(tmp); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static long put_compat_ipmi_msg(struct ipmi_msg *p64, | ||
567 | struct compat_ipmi_msg __user *p32) | ||
568 | { | ||
569 | if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || | ||
570 | __put_user(p64->netfn, &p32->netfn) || | ||
571 | __put_user(p64->cmd, &p32->cmd) || | ||
572 | __put_user(p64->data_len, &p32->data_len)) | ||
573 | return -EFAULT; | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static long get_compat_ipmi_req(struct ipmi_req *p64, | ||
578 | struct compat_ipmi_req __user *p32) | ||
579 | { | ||
580 | |||
581 | compat_uptr_t tmp; | ||
582 | |||
583 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
584 | __get_user(tmp, &p32->addr) || | ||
585 | __get_user(p64->addr_len, &p32->addr_len) || | ||
586 | __get_user(p64->msgid, &p32->msgid) || | ||
587 | get_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
588 | return -EFAULT; | ||
589 | p64->addr = compat_ptr(tmp); | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, | ||
594 | struct compat_ipmi_req_settime __user *p32) | ||
595 | { | ||
596 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
597 | get_compat_ipmi_req(&p64->req, &p32->req) || | ||
598 | __get_user(p64->retries, &p32->retries) || | ||
599 | __get_user(p64->retry_time_ms, &p32->retry_time_ms)) | ||
600 | return -EFAULT; | ||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static long get_compat_ipmi_recv(struct ipmi_recv *p64, | ||
605 | struct compat_ipmi_recv __user *p32) | ||
606 | { | ||
607 | compat_uptr_t tmp; | ||
608 | |||
609 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
610 | __get_user(p64->recv_type, &p32->recv_type) || | ||
611 | __get_user(tmp, &p32->addr) || | ||
612 | __get_user(p64->addr_len, &p32->addr_len) || | ||
613 | __get_user(p64->msgid, &p32->msgid) || | ||
614 | get_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
615 | return -EFAULT; | ||
616 | p64->addr = compat_ptr(tmp); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static long put_compat_ipmi_recv(struct ipmi_recv *p64, | ||
621 | struct compat_ipmi_recv __user *p32) | ||
622 | { | ||
623 | if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || | ||
624 | __put_user(p64->recv_type, &p32->recv_type) || | ||
625 | __put_user(p64->addr_len, &p32->addr_len) || | ||
626 | __put_user(p64->msgid, &p32->msgid) || | ||
627 | put_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
628 | return -EFAULT; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Handle compatibility ioctls | ||
634 | */ | ||
635 | static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, | ||
636 | unsigned long arg) | ||
637 | { | ||
638 | int rc; | ||
639 | struct ipmi_file_private *priv = filep->private_data; | ||
640 | |||
641 | switch(cmd) { | ||
642 | case COMPAT_IPMICTL_SEND_COMMAND: | ||
643 | { | ||
644 | struct ipmi_req rp; | ||
645 | |||
646 | if (get_compat_ipmi_req(&rp, compat_ptr(arg))) | ||
647 | return -EFAULT; | ||
648 | |||
649 | return handle_send_req(priv->user, &rp, | ||
650 | priv->default_retries, | ||
651 | priv->default_retry_time_ms); | ||
652 | } | ||
653 | case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: | ||
654 | { | ||
655 | struct ipmi_req_settime sp; | ||
656 | |||
657 | if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg))) | ||
658 | return -EFAULT; | ||
659 | |||
660 | return handle_send_req(priv->user, &sp.req, | ||
661 | sp.retries, sp.retry_time_ms); | ||
662 | } | ||
663 | case COMPAT_IPMICTL_RECEIVE_MSG: | ||
664 | case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: | ||
665 | { | ||
666 | struct ipmi_recv *precv64, recv64; | ||
667 | |||
668 | if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) | ||
669 | return -EFAULT; | ||
670 | |||
671 | precv64 = compat_alloc_user_space(sizeof(recv64)); | ||
672 | if (copy_to_user(precv64, &recv64, sizeof(recv64))) | ||
673 | return -EFAULT; | ||
674 | |||
675 | rc = ipmi_ioctl(filep->f_dentry->d_inode, filep, | ||
676 | ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) | ||
677 | ? IPMICTL_RECEIVE_MSG | ||
678 | : IPMICTL_RECEIVE_MSG_TRUNC), | ||
679 | (long) precv64); | ||
680 | if (rc != 0) | ||
681 | return rc; | ||
682 | |||
683 | if (copy_from_user(&recv64, precv64, sizeof(recv64))) | ||
684 | return -EFAULT; | ||
685 | |||
686 | if (put_compat_ipmi_recv(&recv64, compat_ptr(arg))) | ||
687 | return -EFAULT; | ||
688 | |||
689 | return rc; | ||
690 | } | ||
691 | default: | ||
692 | return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg); | ||
693 | } | ||
694 | } | ||
695 | #endif | ||
503 | 696 | ||
504 | static struct file_operations ipmi_fops = { | 697 | static struct file_operations ipmi_fops = { |
505 | .owner = THIS_MODULE, | 698 | .owner = THIS_MODULE, |
506 | .ioctl = ipmi_ioctl, | 699 | .ioctl = ipmi_ioctl, |
700 | #ifdef CONFIG_COMPAT | ||
701 | .compat_ioctl = compat_ipmi_ioctl, | ||
702 | #endif | ||
507 | .open = ipmi_open, | 703 | .open = ipmi_open, |
508 | .release = ipmi_release, | 704 | .release = ipmi_release, |
509 | .fasync = ipmi_fasync, | 705 | .fasync = ipmi_fasync, |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 0c81652eaba6..1813d0d198f1 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); | |||
54 | 54 | ||
55 | static int initialized = 0; | 55 | static int initialized = 0; |
56 | 56 | ||
57 | static struct proc_dir_entry *proc_ipmi_root = NULL; | 57 | #ifdef CONFIG_PROC_FS |
58 | struct proc_dir_entry *proc_ipmi_root = NULL; | ||
59 | #endif /* CONFIG_PROC_FS */ | ||
58 | 60 | ||
59 | #define MAX_EVENTS_IN_QUEUE 25 | 61 | #define MAX_EVENTS_IN_QUEUE 25 |
60 | 62 | ||
@@ -124,11 +126,13 @@ struct ipmi_channel | |||
124 | unsigned char protocol; | 126 | unsigned char protocol; |
125 | }; | 127 | }; |
126 | 128 | ||
129 | #ifdef CONFIG_PROC_FS | ||
127 | struct ipmi_proc_entry | 130 | struct ipmi_proc_entry |
128 | { | 131 | { |
129 | char *name; | 132 | char *name; |
130 | struct ipmi_proc_entry *next; | 133 | struct ipmi_proc_entry *next; |
131 | }; | 134 | }; |
135 | #endif | ||
132 | 136 | ||
133 | #define IPMI_IPMB_NUM_SEQ 64 | 137 | #define IPMI_IPMB_NUM_SEQ 64 |
134 | #define IPMI_MAX_CHANNELS 8 | 138 | #define IPMI_MAX_CHANNELS 8 |
@@ -156,10 +160,13 @@ struct ipmi_smi | |||
156 | struct ipmi_smi_handlers *handlers; | 160 | struct ipmi_smi_handlers *handlers; |
157 | void *send_info; | 161 | void *send_info; |
158 | 162 | ||
163 | #ifdef CONFIG_PROC_FS | ||
159 | /* A list of proc entries for this interface. This does not | 164 | /* A list of proc entries for this interface. This does not |
160 | need a lock, only one thread creates it and only one thread | 165 | need a lock, only one thread creates it and only one thread |
161 | destroys it. */ | 166 | destroys it. */ |
167 | spinlock_t proc_entry_lock; | ||
162 | struct ipmi_proc_entry *proc_entries; | 168 | struct ipmi_proc_entry *proc_entries; |
169 | #endif | ||
163 | 170 | ||
164 | /* A table of sequence numbers for this interface. We use the | 171 | /* A table of sequence numbers for this interface. We use the |
165 | sequence numbers for IPMB messages that go out of the | 172 | 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, | |||
1470 | read_proc_t *read_proc, write_proc_t *write_proc, | 1477 | read_proc_t *read_proc, write_proc_t *write_proc, |
1471 | void *data, struct module *owner) | 1478 | void *data, struct module *owner) |
1472 | { | 1479 | { |
1473 | struct proc_dir_entry *file; | ||
1474 | int rv = 0; | 1480 | int rv = 0; |
1481 | #ifdef CONFIG_PROC_FS | ||
1482 | struct proc_dir_entry *file; | ||
1475 | struct ipmi_proc_entry *entry; | 1483 | struct ipmi_proc_entry *entry; |
1476 | 1484 | ||
1477 | /* Create a list element. */ | 1485 | /* Create a list element. */ |
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, | |||
1497 | file->write_proc = write_proc; | 1505 | file->write_proc = write_proc; |
1498 | file->owner = owner; | 1506 | file->owner = owner; |
1499 | 1507 | ||
1508 | spin_lock(&smi->proc_entry_lock); | ||
1500 | /* Stick it on the list. */ | 1509 | /* Stick it on the list. */ |
1501 | entry->next = smi->proc_entries; | 1510 | entry->next = smi->proc_entries; |
1502 | smi->proc_entries = entry; | 1511 | smi->proc_entries = entry; |
1512 | spin_unlock(&smi->proc_entry_lock); | ||
1503 | } | 1513 | } |
1514 | #endif /* CONFIG_PROC_FS */ | ||
1504 | 1515 | ||
1505 | return rv; | 1516 | return rv; |
1506 | } | 1517 | } |
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num) | |||
1509 | { | 1520 | { |
1510 | int rv = 0; | 1521 | int rv = 0; |
1511 | 1522 | ||
1523 | #ifdef CONFIG_PROC_FS | ||
1512 | sprintf(smi->proc_dir_name, "%d", num); | 1524 | sprintf(smi->proc_dir_name, "%d", num); |
1513 | smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); | 1525 | smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); |
1514 | if (!smi->proc_dir) | 1526 | if (!smi->proc_dir) |
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num) | |||
1531 | rv = ipmi_smi_add_proc_entry(smi, "version", | 1543 | rv = ipmi_smi_add_proc_entry(smi, "version", |
1532 | version_file_read_proc, NULL, | 1544 | version_file_read_proc, NULL, |
1533 | smi, THIS_MODULE); | 1545 | smi, THIS_MODULE); |
1546 | #endif /* CONFIG_PROC_FS */ | ||
1534 | 1547 | ||
1535 | return rv; | 1548 | return rv; |
1536 | } | 1549 | } |
1537 | 1550 | ||
1538 | static void remove_proc_entries(ipmi_smi_t smi) | 1551 | static void remove_proc_entries(ipmi_smi_t smi) |
1539 | { | 1552 | { |
1553 | #ifdef CONFIG_PROC_FS | ||
1540 | struct ipmi_proc_entry *entry; | 1554 | struct ipmi_proc_entry *entry; |
1541 | 1555 | ||
1556 | spin_lock(&smi->proc_entry_lock); | ||
1542 | while (smi->proc_entries) { | 1557 | while (smi->proc_entries) { |
1543 | entry = smi->proc_entries; | 1558 | entry = smi->proc_entries; |
1544 | smi->proc_entries = entry->next; | 1559 | smi->proc_entries = entry->next; |
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi) | |||
1547 | kfree(entry->name); | 1562 | kfree(entry->name); |
1548 | kfree(entry); | 1563 | kfree(entry); |
1549 | } | 1564 | } |
1565 | spin_unlock(&smi->proc_entry_lock); | ||
1550 | remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); | 1566 | remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); |
1567 | #endif /* CONFIG_PROC_FS */ | ||
1551 | } | 1568 | } |
1552 | 1569 | ||
1553 | static int | 1570 | static int |
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1694 | new_intf->seq_table[j].seqid = 0; | 1711 | new_intf->seq_table[j].seqid = 0; |
1695 | } | 1712 | } |
1696 | new_intf->curr_seq = 0; | 1713 | new_intf->curr_seq = 0; |
1714 | #ifdef CONFIG_PROC_FS | ||
1715 | spin_lock_init(&(new_intf->proc_entry_lock)); | ||
1716 | #endif | ||
1697 | spin_lock_init(&(new_intf->waiting_msgs_lock)); | 1717 | spin_lock_init(&(new_intf->waiting_msgs_lock)); |
1698 | INIT_LIST_HEAD(&(new_intf->waiting_msgs)); | 1718 | INIT_LIST_HEAD(&(new_intf->waiting_msgs)); |
1699 | spin_lock_init(&(new_intf->events_lock)); | 1719 | spin_lock_init(&(new_intf->events_lock)); |
@@ -2747,16 +2767,13 @@ static struct timer_list ipmi_timer; | |||
2747 | the queue and this silliness can go away. */ | 2767 | the queue and this silliness can go away. */ |
2748 | #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) | 2768 | #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) |
2749 | 2769 | ||
2750 | static volatile int stop_operation = 0; | 2770 | static atomic_t stop_operation; |
2751 | static volatile int timer_stopped = 0; | ||
2752 | static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME; | 2771 | static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME; |
2753 | 2772 | ||
2754 | static void ipmi_timeout(unsigned long data) | 2773 | static void ipmi_timeout(unsigned long data) |
2755 | { | 2774 | { |
2756 | if (stop_operation) { | 2775 | if (atomic_read(&stop_operation)) |
2757 | timer_stopped = 1; | ||
2758 | return; | 2776 | return; |
2759 | } | ||
2760 | 2777 | ||
2761 | ticks_to_req_ev--; | 2778 | ticks_to_req_ev--; |
2762 | if (ticks_to_req_ev == 0) { | 2779 | if (ticks_to_req_ev == 0) { |
@@ -2766,8 +2783,7 @@ static void ipmi_timeout(unsigned long data) | |||
2766 | 2783 | ||
2767 | ipmi_timeout_handler(IPMI_TIMEOUT_TIME); | 2784 | ipmi_timeout_handler(IPMI_TIMEOUT_TIME); |
2768 | 2785 | ||
2769 | ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES; | 2786 | mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); |
2770 | add_timer(&ipmi_timer); | ||
2771 | } | 2787 | } |
2772 | 2788 | ||
2773 | 2789 | ||
@@ -3089,6 +3105,7 @@ static int ipmi_init_msghandler(void) | |||
3089 | ipmi_interfaces[i] = NULL; | 3105 | ipmi_interfaces[i] = NULL; |
3090 | } | 3106 | } |
3091 | 3107 | ||
3108 | #ifdef CONFIG_PROC_FS | ||
3092 | proc_ipmi_root = proc_mkdir("ipmi", NULL); | 3109 | proc_ipmi_root = proc_mkdir("ipmi", NULL); |
3093 | if (!proc_ipmi_root) { | 3110 | if (!proc_ipmi_root) { |
3094 | printk(KERN_ERR PFX "Unable to create IPMI proc dir"); | 3111 | printk(KERN_ERR PFX "Unable to create IPMI proc dir"); |
@@ -3096,6 +3113,7 @@ static int ipmi_init_msghandler(void) | |||
3096 | } | 3113 | } |
3097 | 3114 | ||
3098 | proc_ipmi_root->owner = THIS_MODULE; | 3115 | proc_ipmi_root->owner = THIS_MODULE; |
3116 | #endif /* CONFIG_PROC_FS */ | ||
3099 | 3117 | ||
3100 | init_timer(&ipmi_timer); | 3118 | init_timer(&ipmi_timer); |
3101 | ipmi_timer.data = 0; | 3119 | ipmi_timer.data = 0; |
@@ -3130,13 +3148,12 @@ static __exit void cleanup_ipmi(void) | |||
3130 | 3148 | ||
3131 | /* Tell the timer to stop, then wait for it to stop. This avoids | 3149 | /* Tell the timer to stop, then wait for it to stop. This avoids |
3132 | problems with race conditions removing the timer here. */ | 3150 | problems with race conditions removing the timer here. */ |
3133 | stop_operation = 1; | 3151 | atomic_inc(&stop_operation); |
3134 | while (!timer_stopped) { | 3152 | del_timer_sync(&ipmi_timer); |
3135 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
3136 | schedule_timeout(1); | ||
3137 | } | ||
3138 | 3153 | ||
3154 | #ifdef CONFIG_PROC_FS | ||
3139 | remove_proc_entry(proc_ipmi_root->name, &proc_root); | 3155 | remove_proc_entry(proc_ipmi_root->name, &proc_root); |
3156 | #endif /* CONFIG_PROC_FS */ | ||
3140 | 3157 | ||
3141 | initialized = 0; | 3158 | initialized = 0; |
3142 | 3159 | ||
@@ -3177,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address); | |||
3177 | EXPORT_SYMBOL(ipmi_set_my_LUN); | 3194 | EXPORT_SYMBOL(ipmi_set_my_LUN); |
3178 | EXPORT_SYMBOL(ipmi_get_my_LUN); | 3195 | EXPORT_SYMBOL(ipmi_get_my_LUN); |
3179 | EXPORT_SYMBOL(ipmi_smi_add_proc_entry); | 3196 | EXPORT_SYMBOL(ipmi_smi_add_proc_entry); |
3197 | EXPORT_SYMBOL(proc_ipmi_root); | ||
3180 | EXPORT_SYMBOL(ipmi_user_set_run_to_completion); | 3198 | 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 cb5cdc6f14bf..f951c30236c9 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -31,10 +31,13 @@ | |||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | 31 | * with this program; if not, write to the Free Software Foundation, Inc., |
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 32 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
33 | */ | 33 | */ |
34 | #include <asm/semaphore.h> | 34 | #include <linux/config.h> |
35 | #include <linux/kdev_t.h> | ||
36 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/proc_fs.h> | ||
37 | #include <linux/string.h> | 38 | #include <linux/string.h> |
39 | #include <linux/completion.h> | ||
40 | #include <linux/kdev_t.h> | ||
38 | #include <linux/ipmi.h> | 41 | #include <linux/ipmi.h> |
39 | #include <linux/ipmi_smi.h> | 42 | #include <linux/ipmi_smi.h> |
40 | 43 | ||
@@ -44,6 +47,18 @@ | |||
44 | /* Where to we insert our poweroff function? */ | 47 | /* Where to we insert our poweroff function? */ |
45 | extern void (*pm_power_off)(void); | 48 | extern void (*pm_power_off)(void); |
46 | 49 | ||
50 | /* Definitions for controlling power off (if the system supports it). It | ||
51 | * conveniently matches the IPMI chassis control values. */ | ||
52 | #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ | ||
53 | #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ | ||
54 | |||
55 | /* the IPMI data command */ | ||
56 | static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
57 | |||
58 | /* parameter definition to allow user to flag power cycle */ | ||
59 | module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); | ||
60 | 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."); | ||
61 | |||
47 | /* Stuff from the get device id command. */ | 62 | /* Stuff from the get device id command. */ |
48 | static unsigned int mfg_id; | 63 | static unsigned int mfg_id; |
49 | static unsigned int prod_id; | 64 | static unsigned int prod_id; |
@@ -75,10 +90,10 @@ static struct ipmi_recv_msg halt_recv_msg = | |||
75 | 90 | ||
76 | static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) | 91 | static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) |
77 | { | 92 | { |
78 | struct semaphore *sem = recv_msg->user_msg_data; | 93 | struct completion *comp = recv_msg->user_msg_data; |
79 | 94 | ||
80 | if (sem) | 95 | if (comp) |
81 | up(sem); | 96 | complete(comp); |
82 | } | 97 | } |
83 | 98 | ||
84 | static struct ipmi_user_hndl ipmi_poweroff_handler = | 99 | static struct ipmi_user_hndl ipmi_poweroff_handler = |
@@ -91,27 +106,27 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, | |||
91 | struct ipmi_addr *addr, | 106 | struct ipmi_addr *addr, |
92 | struct kernel_ipmi_msg *send_msg) | 107 | struct kernel_ipmi_msg *send_msg) |
93 | { | 108 | { |
94 | int rv; | 109 | int rv; |
95 | struct semaphore sem; | 110 | struct completion comp; |
96 | 111 | ||
97 | sema_init (&sem, 0); | 112 | init_completion(&comp); |
98 | 113 | ||
99 | rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem, | 114 | rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp, |
100 | &halt_smi_msg, &halt_recv_msg, 0); | 115 | &halt_smi_msg, &halt_recv_msg, 0); |
101 | if (rv) | 116 | if (rv) |
102 | return rv; | 117 | return rv; |
103 | 118 | ||
104 | down (&sem); | 119 | wait_for_completion(&comp); |
105 | 120 | ||
106 | return halt_recv_msg.msg.data[0]; | 121 | return halt_recv_msg.msg.data[0]; |
107 | } | 122 | } |
108 | 123 | ||
109 | /* We are in run-to-completion mode, no semaphore is desired. */ | 124 | /* We are in run-to-completion mode, no completion is desired. */ |
110 | static int ipmi_request_in_rc_mode(ipmi_user_t user, | 125 | static int ipmi_request_in_rc_mode(ipmi_user_t user, |
111 | struct ipmi_addr *addr, | 126 | struct ipmi_addr *addr, |
112 | struct kernel_ipmi_msg *send_msg) | 127 | struct kernel_ipmi_msg *send_msg) |
113 | { | 128 | { |
114 | int rv; | 129 | int rv; |
115 | 130 | ||
116 | rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, | 131 | rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, |
117 | &halt_smi_msg, &halt_recv_msg, 0); | 132 | &halt_smi_msg, &halt_recv_msg, 0); |
@@ -349,26 +364,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) | |||
349 | smi_addr.channel = IPMI_BMC_CHANNEL; | 364 | smi_addr.channel = IPMI_BMC_CHANNEL; |
350 | smi_addr.lun = 0; | 365 | smi_addr.lun = 0; |
351 | 366 | ||
352 | printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); | 367 | powercyclefailed: |
368 | printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", | ||
369 | ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); | ||
353 | 370 | ||
354 | /* | 371 | /* |
355 | * Power down | 372 | * Power down |
356 | */ | 373 | */ |
357 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; | 374 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; |
358 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; | 375 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; |
359 | data[0] = 0; /* Power down */ | 376 | data[0] = poweroff_control; |
360 | send_msg.data = data; | 377 | send_msg.data = data; |
361 | send_msg.data_len = sizeof(data); | 378 | send_msg.data_len = sizeof(data); |
362 | rv = ipmi_request_in_rc_mode(user, | 379 | rv = ipmi_request_in_rc_mode(user, |
363 | (struct ipmi_addr *) &smi_addr, | 380 | (struct ipmi_addr *) &smi_addr, |
364 | &send_msg); | 381 | &send_msg); |
365 | if (rv) { | 382 | if (rv) { |
366 | printk(KERN_ERR PFX "Unable to send chassis powerdown message," | 383 | switch (poweroff_control) { |
367 | " IPMI error 0x%x\n", rv); | 384 | case IPMI_CHASSIS_POWER_CYCLE: |
368 | goto out; | 385 | /* power cycle failed, default to power down */ |
386 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
387 | "cycle message, IPMI error 0x%x\n", rv); | ||
388 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
389 | goto powercyclefailed; | ||
390 | |||
391 | case IPMI_CHASSIS_POWER_DOWN: | ||
392 | default: | ||
393 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
394 | "down message, IPMI error 0x%x\n", rv); | ||
395 | break; | ||
396 | } | ||
369 | } | 397 | } |
370 | 398 | ||
371 | out: | ||
372 | return; | 399 | return; |
373 | } | 400 | } |
374 | 401 | ||
@@ -430,7 +457,8 @@ static void ipmi_po_new_smi(int if_num) | |||
430 | if (ready) | 457 | if (ready) |
431 | return; | 458 | return; |
432 | 459 | ||
433 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); | 460 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, |
461 | &ipmi_user); | ||
434 | if (rv) { | 462 | if (rv) { |
435 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", | 463 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", |
436 | rv); | 464 | rv); |
@@ -509,21 +537,84 @@ static struct ipmi_smi_watcher smi_watcher = | |||
509 | }; | 537 | }; |
510 | 538 | ||
511 | 539 | ||
540 | #ifdef CONFIG_PROC_FS | ||
541 | /* displays properties to proc */ | ||
542 | static int proc_read_chassctrl(char *page, char **start, off_t off, int count, | ||
543 | int *eof, void *data) | ||
544 | { | ||
545 | return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", | ||
546 | poweroff_control); | ||
547 | } | ||
548 | |||
549 | /* process property writes from proc */ | ||
550 | static int proc_write_chassctrl(struct file *file, const char *buffer, | ||
551 | unsigned long count, void *data) | ||
552 | { | ||
553 | int rv = count; | ||
554 | unsigned int newval = 0; | ||
555 | |||
556 | sscanf(buffer, "%d", &newval); | ||
557 | switch (newval) { | ||
558 | case IPMI_CHASSIS_POWER_CYCLE: | ||
559 | printk(KERN_INFO PFX "power cycle is now enabled\n"); | ||
560 | poweroff_control = newval; | ||
561 | break; | ||
562 | |||
563 | case IPMI_CHASSIS_POWER_DOWN: | ||
564 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
565 | break; | ||
566 | |||
567 | default: | ||
568 | rv = -EINVAL; | ||
569 | break; | ||
570 | } | ||
571 | |||
572 | return rv; | ||
573 | } | ||
574 | #endif /* CONFIG_PROC_FS */ | ||
575 | |||
512 | /* | 576 | /* |
513 | * Startup and shutdown functions. | 577 | * Startup and shutdown functions. |
514 | */ | 578 | */ |
515 | static int ipmi_poweroff_init (void) | 579 | static int ipmi_poweroff_init (void) |
516 | { | 580 | { |
517 | int rv; | 581 | int rv; |
582 | struct proc_dir_entry *file; | ||
518 | 583 | ||
519 | printk ("Copyright (C) 2004 MontaVista Software -" | 584 | printk ("Copyright (C) 2004 MontaVista Software -" |
520 | " IPMI Powerdown via sys_reboot version " | 585 | " IPMI Powerdown via sys_reboot version " |
521 | IPMI_POWEROFF_VERSION ".\n"); | 586 | IPMI_POWEROFF_VERSION ".\n"); |
522 | 587 | ||
588 | switch (poweroff_control) { | ||
589 | case IPMI_CHASSIS_POWER_CYCLE: | ||
590 | printk(KERN_INFO PFX "Power cycle is enabled.\n"); | ||
591 | break; | ||
592 | |||
593 | case IPMI_CHASSIS_POWER_DOWN: | ||
594 | default: | ||
595 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
596 | break; | ||
597 | } | ||
598 | |||
523 | rv = ipmi_smi_watcher_register(&smi_watcher); | 599 | rv = ipmi_smi_watcher_register(&smi_watcher); |
524 | if (rv) | 600 | if (rv) { |
525 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); | 601 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); |
602 | goto out_err; | ||
603 | } | ||
604 | |||
605 | #ifdef CONFIG_PROC_FS | ||
606 | file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); | ||
607 | if (!file) { | ||
608 | printk(KERN_ERR PFX "Unable to create proc power control\n"); | ||
609 | } else { | ||
610 | file->nlink = 1; | ||
611 | file->read_proc = proc_read_chassctrl; | ||
612 | file->write_proc = proc_write_chassctrl; | ||
613 | file->owner = THIS_MODULE; | ||
614 | } | ||
615 | #endif | ||
526 | 616 | ||
617 | out_err: | ||
527 | return rv; | 618 | return rv; |
528 | } | 619 | } |
529 | 620 | ||
@@ -532,6 +623,10 @@ static __exit void ipmi_poweroff_cleanup(void) | |||
532 | { | 623 | { |
533 | int rv; | 624 | int rv; |
534 | 625 | ||
626 | #ifdef CONFIG_PROC_FS | ||
627 | remove_proc_entry("poweroff_control", proc_ipmi_root); | ||
628 | #endif | ||
629 | |||
535 | ipmi_smi_watcher_unregister(&smi_watcher); | 630 | ipmi_smi_watcher_unregister(&smi_watcher); |
536 | 631 | ||
537 | if (ready) { | 632 | if (ready) { |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 601c7fccb4cf..1bbf507adda5 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty) | |||
1756 | } | 1756 | } |
1757 | 1757 | ||
1758 | 1758 | ||
1759 | static int __init register_ioregion(void) | 1759 | static int __devinit register_ioregion(void) |
1760 | { | 1760 | { |
1761 | int count, done=0; | 1761 | int count, done=0; |
1762 | for (count=0; count < BOARD_COUNT; count++ ) { | 1762 | for (count=0; count < BOARD_COUNT; count++ ) { |
@@ -1771,7 +1771,7 @@ static int __init register_ioregion(void) | |||
1771 | return done; | 1771 | return done; |
1772 | } | 1772 | } |
1773 | 1773 | ||
1774 | static void __exit unregister_ioregion(void) | 1774 | static void unregister_ioregion(void) |
1775 | { | 1775 | { |
1776 | int count; | 1776 | int count; |
1777 | for (count=0; count < BOARD_COUNT; count++ ) | 1777 | for (count=0; count < BOARD_COUNT; count++ ) |
@@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = { | |||
1803 | .tiocmset = isicom_tiocmset, | 1803 | .tiocmset = isicom_tiocmset, |
1804 | }; | 1804 | }; |
1805 | 1805 | ||
1806 | static int __init register_drivers(void) | 1806 | static int __devinit register_drivers(void) |
1807 | { | 1807 | { |
1808 | int error; | 1808 | int error; |
1809 | 1809 | ||
@@ -1834,7 +1834,7 @@ static int __init register_drivers(void) | |||
1834 | return 0; | 1834 | return 0; |
1835 | } | 1835 | } |
1836 | 1836 | ||
1837 | static void __exit unregister_drivers(void) | 1837 | static void unregister_drivers(void) |
1838 | { | 1838 | { |
1839 | int error = tty_unregister_driver(isicom_normal); | 1839 | int error = tty_unregister_driver(isicom_normal); |
1840 | if (error) | 1840 | if (error) |
@@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void) | |||
1842 | put_tty_driver(isicom_normal); | 1842 | put_tty_driver(isicom_normal); |
1843 | } | 1843 | } |
1844 | 1844 | ||
1845 | static int __init register_isr(void) | 1845 | static int __devinit register_isr(void) |
1846 | { | 1846 | { |
1847 | int count, done=0; | 1847 | int count, done=0; |
1848 | unsigned long irqflags; | 1848 | unsigned long irqflags; |
@@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void) | |||
1883 | } | 1883 | } |
1884 | } | 1884 | } |
1885 | 1885 | ||
1886 | static int __init isicom_init(void) | 1886 | static int __devinit isicom_init(void) |
1887 | { | 1887 | { |
1888 | int card, channel, base; | 1888 | int card, channel, base; |
1889 | struct isi_port * port; | 1889 | struct isi_port * port; |
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index c02a21dbad5d..52a073eee201 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c | |||
@@ -407,7 +407,6 @@ static unsigned long stli_eisamemprobeaddrs[] = { | |||
407 | }; | 407 | }; |
408 | 408 | ||
409 | static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long); | 409 | static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long); |
410 | int stli_eisaprobe = STLI_EISAPROBE; | ||
411 | 410 | ||
412 | /* | 411 | /* |
413 | * Define the Stallion PCI vendor and device IDs. | 412 | * Define the Stallion PCI vendor and device IDs. |
@@ -4685,7 +4684,7 @@ static int stli_initbrds(void) | |||
4685 | #ifdef MODULE | 4684 | #ifdef MODULE |
4686 | stli_argbrds(); | 4685 | stli_argbrds(); |
4687 | #endif | 4686 | #endif |
4688 | if (stli_eisaprobe) | 4687 | if (STLI_EISAPROBE) |
4689 | stli_findeisabrds(); | 4688 | stli_findeisabrds(); |
4690 | #ifdef CONFIG_PCI | 4689 | #ifdef CONFIG_PCI |
4691 | stli_findpcibrds(); | 4690 | stli_findpcibrds(); |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e3085b22a365..42187381506b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -23,7 +23,10 @@ | |||
23 | #include <linux/devfs_fs_kernel.h> | 23 | #include <linux/devfs_fs_kernel.h> |
24 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/highmem.h> | ||
27 | #include <linux/crash_dump.h> | ||
26 | #include <linux/backing-dev.h> | 28 | #include <linux/backing-dev.h> |
29 | #include <linux/bootmem.h> | ||
27 | 30 | ||
28 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
29 | #include <asm/io.h> | 32 | #include <asm/io.h> |
@@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) | |||
273 | return mmap_mem(file, vma); | 276 | return mmap_mem(file, vma); |
274 | } | 277 | } |
275 | 278 | ||
279 | #ifdef CONFIG_CRASH_DUMP | ||
280 | /* | ||
281 | * Read memory corresponding to the old kernel. | ||
282 | */ | ||
283 | static ssize_t read_oldmem(struct file *file, char __user *buf, | ||
284 | size_t count, loff_t *ppos) | ||
285 | { | ||
286 | unsigned long pfn, offset; | ||
287 | size_t read = 0, csize; | ||
288 | int rc = 0; | ||
289 | |||
290 | while (count) { | ||
291 | pfn = *ppos / PAGE_SIZE; | ||
292 | if (pfn > saved_max_pfn) | ||
293 | return read; | ||
294 | |||
295 | offset = (unsigned long)(*ppos % PAGE_SIZE); | ||
296 | if (count > PAGE_SIZE - offset) | ||
297 | csize = PAGE_SIZE - offset; | ||
298 | else | ||
299 | csize = count; | ||
300 | |||
301 | rc = copy_oldmem_page(pfn, buf, csize, offset, 1); | ||
302 | if (rc < 0) | ||
303 | return rc; | ||
304 | buf += csize; | ||
305 | *ppos += csize; | ||
306 | read += csize; | ||
307 | count -= csize; | ||
308 | } | ||
309 | return read; | ||
310 | } | ||
311 | #endif | ||
312 | |||
276 | extern long vread(char *buf, char *addr, unsigned long count); | 313 | extern long vread(char *buf, char *addr, unsigned long count); |
277 | extern long vwrite(char *buf, char *addr, unsigned long count); | 314 | extern long vwrite(char *buf, char *addr, unsigned long count); |
278 | 315 | ||
@@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp) | |||
721 | #define read_full read_zero | 758 | #define read_full read_zero |
722 | #define open_mem open_port | 759 | #define open_mem open_port |
723 | #define open_kmem open_mem | 760 | #define open_kmem open_mem |
761 | #define open_oldmem open_mem | ||
724 | 762 | ||
725 | static struct file_operations mem_fops = { | 763 | static struct file_operations mem_fops = { |
726 | .llseek = memory_lseek, | 764 | .llseek = memory_lseek, |
@@ -770,6 +808,13 @@ static struct file_operations full_fops = { | |||
770 | .write = write_full, | 808 | .write = write_full, |
771 | }; | 809 | }; |
772 | 810 | ||
811 | #ifdef CONFIG_CRASH_DUMP | ||
812 | static struct file_operations oldmem_fops = { | ||
813 | .read = read_oldmem, | ||
814 | .open = open_oldmem, | ||
815 | }; | ||
816 | #endif | ||
817 | |||
773 | static ssize_t kmsg_write(struct file * file, const char __user * buf, | 818 | static ssize_t kmsg_write(struct file * file, const char __user * buf, |
774 | size_t count, loff_t *ppos) | 819 | size_t count, loff_t *ppos) |
775 | { | 820 | { |
@@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp) | |||
825 | case 11: | 870 | case 11: |
826 | filp->f_op = &kmsg_fops; | 871 | filp->f_op = &kmsg_fops; |
827 | break; | 872 | break; |
873 | #ifdef CONFIG_CRASH_DUMP | ||
874 | case 12: | ||
875 | filp->f_op = &oldmem_fops; | ||
876 | break; | ||
877 | #endif | ||
828 | default: | 878 | default: |
829 | return -ENXIO; | 879 | return -ENXIO; |
830 | } | 880 | } |
@@ -854,6 +904,9 @@ static const struct { | |||
854 | {8, "random", S_IRUGO | S_IWUSR, &random_fops}, | 904 | {8, "random", S_IRUGO | S_IWUSR, &random_fops}, |
855 | {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, | 905 | {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, |
856 | {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, | 906 | {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, |
907 | #ifdef CONFIG_CRASH_DUMP | ||
908 | {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, | ||
909 | #endif | ||
857 | }; | 910 | }; |
858 | 911 | ||
859 | static struct class *mem_class; | 912 | static struct class *mem_class; |
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 3115d318b997..31cf84d69026 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c | |||
@@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; | |||
66 | extern int rtc_DP8570A_init(void); | 66 | extern int rtc_DP8570A_init(void); |
67 | extern int rtc_MK48T08_init(void); | 67 | extern int rtc_MK48T08_init(void); |
68 | extern int pmu_device_init(void); | 68 | extern int pmu_device_init(void); |
69 | extern int tosh_init(void); | ||
70 | extern int i8k_init(void); | ||
71 | 69 | ||
72 | #ifdef CONFIG_PROC_FS | 70 | #ifdef CONFIG_PROC_FS |
73 | static void *misc_seq_start(struct seq_file *seq, loff_t *pos) | 71 | static void *misc_seq_start(struct seq_file *seq, loff_t *pos) |
@@ -314,12 +312,6 @@ static int __init misc_init(void) | |||
314 | #ifdef CONFIG_PMAC_PBOOK | 312 | #ifdef CONFIG_PMAC_PBOOK |
315 | pmu_device_init(); | 313 | pmu_device_init(); |
316 | #endif | 314 | #endif |
317 | #ifdef CONFIG_TOSHIBA | ||
318 | tosh_init(); | ||
319 | #endif | ||
320 | #ifdef CONFIG_I8K | ||
321 | i8k_init(); | ||
322 | #endif | ||
323 | if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { | 315 | if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { |
324 | printk("unable to get major %d for misc devices\n", | 316 | printk("unable to get major %d for misc devices\n", |
325 | MISC_MAJOR); | 317 | MISC_MAJOR); |
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index ab00f51475df..613aed9e1840 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c | |||
@@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, | |||
107 | spin_unlock_irqrestore(&dsp_lock, flags); | 107 | spin_unlock_irqrestore(&dsp_lock, flags); |
108 | } | 108 | } |
109 | 109 | ||
110 | void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, | 110 | static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, |
111 | unsigned char ucValue) | 111 | unsigned char ucValue) |
112 | { | 112 | { |
113 | DSP_ISA_SLAVE_CONTROL rSlaveControl; | 113 | DSP_ISA_SLAVE_CONTROL rSlaveControl; |
114 | DSP_ISA_SLAVE_CONTROL rSlaveControl_Save; | 114 | DSP_ISA_SLAVE_CONTROL rSlaveControl_Save; |
@@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, | |||
141 | 141 | ||
142 | } | 142 | } |
143 | 143 | ||
144 | #if 0 | ||
144 | unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, | 145 | unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, |
145 | unsigned uIndex) | 146 | unsigned uIndex) |
146 | { | 147 | { |
@@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, | |||
167 | 168 | ||
168 | return ucValue; | 169 | return ucValue; |
169 | } | 170 | } |
171 | #endif /* 0 */ | ||
170 | 172 | ||
171 | int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | 173 | int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, |
172 | unsigned short *pIrqMap, | 174 | unsigned short *pIrqMap, |
diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h index 3e7d020d1bf4..270431ca7dae 100644 --- a/drivers/char/mwave/3780i.h +++ b/drivers/char/mwave/3780i.h | |||
@@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO, | |||
338 | unsigned long ulMsaAddr); | 338 | unsigned long ulMsaAddr); |
339 | void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, | 339 | void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, |
340 | unsigned long ulMsaAddr, unsigned short usValue); | 340 | unsigned long ulMsaAddr, unsigned short usValue); |
341 | void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, | ||
342 | unsigned char ucValue); | ||
343 | unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, | ||
344 | unsigned uIndex); | ||
345 | int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, | 341 | int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, |
346 | unsigned short *pusIPCSource); | 342 | unsigned short *pusIPCSource); |
347 | 343 | ||
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index ab650cd6efc0..d6c72e0934e2 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c | |||
@@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData) | |||
242 | { | 242 | { |
243 | int retval = 0; | 243 | int retval = 0; |
244 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; | 244 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; |
245 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
246 | struct resource *pres; | 245 | struct resource *pres; |
247 | #endif | ||
248 | 246 | ||
249 | PRINTK_2(TRACE_TP3780I, | 247 | PRINTK_2(TRACE_TP3780I, |
250 | "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData); | 248 | "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData); |
251 | 249 | ||
252 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
253 | pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); | 250 | pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); |
254 | if ( pres == NULL ) retval = -EIO; | 251 | if ( pres == NULL ) retval = -EIO; |
255 | #else | 252 | |
256 | retval = check_region(pSettings->usDspBaseIO, 16); | ||
257 | if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); | ||
258 | #endif | ||
259 | if (retval) { | 253 | if (retval) { |
260 | PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO); | 254 | PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO); |
261 | retval = -EIO; | 255 | retval = -EIO; |
@@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData) | |||
292 | int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | 286 | int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) |
293 | { | 287 | { |
294 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; | 288 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; |
295 | BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE; | 289 | BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE; |
296 | 290 | ||
297 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); | 291 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); |
298 | 292 | ||
@@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
397 | if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { | 391 | if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { |
398 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n"); | 392 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n"); |
399 | goto exit_cleanup; | 393 | goto exit_cleanup; |
400 | } else { | ||
401 | bDSPEnabled = TRUE; | ||
402 | } | 394 | } |
403 | 395 | ||
404 | EnableSRAM(pBDData); | 396 | EnableSRAM(pBDData); |
@@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
411 | 403 | ||
412 | exit_cleanup: | 404 | exit_cleanup: |
413 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); | 405 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); |
414 | if (bDSPEnabled) | ||
415 | dsp3780I_DisableDSP(pSettings); | ||
416 | if (bDSPPoweredUp) | 406 | if (bDSPPoweredUp) |
417 | smapi_set_DSP_power_state(FALSE); | 407 | smapi_set_DSP_power_state(FALSE); |
418 | if (bInterruptAllocated) { | 408 | if (bInterruptAllocated) { |
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index b3dbff1cf967..5079beda69b5 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -960,7 +960,7 @@ static char hdlc_unregister_fail[] __exitdata = | |||
960 | static void __exit n_hdlc_exit(void) | 960 | static void __exit n_hdlc_exit(void) |
961 | { | 961 | { |
962 | /* Release tty registration of line discipline */ | 962 | /* Release tty registration of line discipline */ |
963 | int status = tty_register_ldisc(N_HDLC, NULL); | 963 | int status = tty_unregister_ldisc(N_HDLC); |
964 | 964 | ||
965 | if (status) | 965 | if (status) |
966 | printk(hdlc_unregister_fail, status); | 966 | printk(hdlc_unregister_fail, status); |
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 3883073ab48f..2291a87e8ada 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c | |||
@@ -200,7 +200,7 @@ static void __exit r3964_exit(void) | |||
200 | 200 | ||
201 | TRACE_M ("cleanup_module()"); | 201 | TRACE_M ("cleanup_module()"); |
202 | 202 | ||
203 | status=tty_register_ldisc(N_R3964, NULL); | 203 | status=tty_unregister_ldisc(N_R3964); |
204 | 204 | ||
205 | if(status!=0) | 205 | if(status!=0) |
206 | { | 206 | { |
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index f63a3fd7ca6f..1af733d07321 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c | |||
@@ -211,12 +211,13 @@ nvram_check_checksum(void) | |||
211 | return rv; | 211 | return rv; |
212 | } | 212 | } |
213 | 213 | ||
214 | void | 214 | static void |
215 | __nvram_set_checksum(void) | 215 | __nvram_set_checksum(void) |
216 | { | 216 | { |
217 | mach_set_checksum(); | 217 | mach_set_checksum(); |
218 | } | 218 | } |
219 | 219 | ||
220 | #if 0 | ||
220 | void | 221 | void |
221 | nvram_set_checksum(void) | 222 | nvram_set_checksum(void) |
222 | { | 223 | { |
@@ -226,6 +227,7 @@ nvram_set_checksum(void) | |||
226 | __nvram_set_checksum(); | 227 | __nvram_set_checksum(); |
227 | spin_unlock_irqrestore(&rtc_lock, flags); | 228 | spin_unlock_irqrestore(&rtc_lock, flags); |
228 | } | 229 | } |
230 | #endif /* 0 */ | ||
229 | 231 | ||
230 | /* | 232 | /* |
231 | * The are the file operation function for user access to /dev/nvram | 233 | * The are the file operation function for user access to /dev/nvram |
@@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte); | |||
921 | EXPORT_SYMBOL(nvram_write_byte); | 923 | EXPORT_SYMBOL(nvram_write_byte); |
922 | EXPORT_SYMBOL(__nvram_check_checksum); | 924 | EXPORT_SYMBOL(__nvram_check_checksum); |
923 | EXPORT_SYMBOL(nvram_check_checksum); | 925 | EXPORT_SYMBOL(nvram_check_checksum); |
924 | EXPORT_SYMBOL(__nvram_set_checksum); | ||
925 | EXPORT_SYMBOL(nvram_set_checksum); | ||
926 | MODULE_ALIAS_MISCDEV(NVRAM_MINOR); | 926 | MODULE_ALIAS_MISCDEV(NVRAM_MINOR); |
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h index e8f3860f4726..01987c6dc398 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); | |||
147 | extern int rio_pcicopy(char *src, char *dst, int n); | 147 | extern int rio_pcicopy(char *src, char *dst, int n); |
148 | extern int rio_minor (struct tty_struct *tty); | 148 | extern int rio_minor (struct tty_struct *tty); |
149 | extern int rio_ismodem (struct tty_struct *tty); | 149 | extern int rio_ismodem (struct tty_struct *tty); |
150 | extern void rio_udelay (int usecs); | ||
151 | 150 | ||
152 | extern void rio_start_card_running (struct Host * HostP); | 151 | extern void rio_start_card_running (struct Host * HostP); |
153 | 152 | ||
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 763893e289b3..7db3370f4972 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) | |||
354 | } | 354 | } |
355 | 355 | ||
356 | 356 | ||
357 | void rio_udelay (int usecs) | ||
358 | { | ||
359 | udelay (usecs); | ||
360 | } | ||
361 | |||
362 | static int rio_set_real_termios (void *ptr) | 357 | static int rio_set_real_termios (void *ptr) |
363 | { | 358 | { |
364 | int rv, modem; | 359 | int rv, modem; |
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index dca941ed10cf..898a126ae3e6 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"; | |||
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/errno.h> | 39 | #include <linux/errno.h> |
40 | #include <linux/delay.h> | ||
40 | #include <asm/io.h> | 41 | #include <asm/io.h> |
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | #include <asm/string.h> | 43 | #include <asm/string.h> |
@@ -1560,14 +1561,14 @@ uint Slot; | |||
1560 | INTERRUPT_DISABLE | BYTE_OPERATION | | 1561 | INTERRUPT_DISABLE | BYTE_OPERATION | |
1561 | SLOW_LINKS | SLOW_AT_BUS); | 1562 | SLOW_LINKS | SLOW_AT_BUS); |
1562 | WBYTE(DpRamP->DpResetTpu, 0xFF); | 1563 | WBYTE(DpRamP->DpResetTpu, 0xFF); |
1563 | rio_udelay (3); | 1564 | udelay(3); |
1564 | 1565 | ||
1565 | rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); | 1566 | rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); |
1566 | WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | | 1567 | WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | |
1567 | INTERRUPT_DISABLE | BYTE_OPERATION | | 1568 | INTERRUPT_DISABLE | BYTE_OPERATION | |
1568 | SLOW_LINKS | SLOW_AT_BUS); | 1569 | SLOW_LINKS | SLOW_AT_BUS); |
1569 | WBYTE(DpRamP->DpResetTpu, 0xFF); | 1570 | WBYTE(DpRamP->DpResetTpu, 0xFF); |
1570 | rio_udelay (3); | 1571 | udelay(3); |
1571 | break; | 1572 | break; |
1572 | #ifdef FUTURE_RELEASE | 1573 | #ifdef FUTURE_RELEASE |
1573 | case RIO_EISA: | 1574 | case RIO_EISA: |
@@ -1599,7 +1600,7 @@ uint Slot; | |||
1599 | DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; | 1600 | DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; |
1600 | DpRamP->DpResetInt = 0xFF; | 1601 | DpRamP->DpResetInt = 0xFF; |
1601 | DpRamP->DpResetTpu = 0xFF; | 1602 | DpRamP->DpResetTpu = 0xFF; |
1602 | rio_udelay (100); | 1603 | udelay(100); |
1603 | /* for (i=0; i<6000; i++); */ | 1604 | /* for (i=0; i<6000; i++); */ |
1604 | /* suspend( 3 ); */ | 1605 | /* suspend( 3 ); */ |
1605 | break; | 1606 | break; |
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index db655002671f..78a321afdf4f 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c | |||
@@ -524,16 +524,16 @@ riotclose(void *ptr) | |||
524 | register uint SysPort = dev; | 524 | register uint SysPort = dev; |
525 | struct ttystatics *tp; /* pointer to our ttystruct */ | 525 | struct ttystatics *tp; /* pointer to our ttystruct */ |
526 | #endif | 526 | #endif |
527 | struct Port *PortP =ptr; /* pointer to the port structure */ | 527 | struct Port *PortP = ptr; /* pointer to the port structure */ |
528 | int deleted = 0; | 528 | int deleted = 0; |
529 | int try = -1; /* Disable the timeouts by setting them to -1 */ | 529 | int try = -1; /* Disable the timeouts by setting them to -1 */ |
530 | int repeat_this = -1; /* Congrats to those having 15 years of | 530 | int repeat_this = -1; /* Congrats to those having 15 years of |
531 | uptime! (You get to break the driver.) */ | 531 | uptime! (You get to break the driver.) */ |
532 | long end_time; | 532 | unsigned long end_time; |
533 | struct tty_struct * tty; | 533 | struct tty_struct * tty; |
534 | unsigned long flags; | 534 | unsigned long flags; |
535 | int Modem; | 535 | int Modem; |
536 | int rv =0; | 536 | int rv = 0; |
537 | 537 | ||
538 | rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); | 538 | rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); |
539 | 539 | ||
@@ -620,7 +620,7 @@ riotclose(void *ptr) | |||
620 | if (repeat_this -- <= 0) { | 620 | if (repeat_this -- <= 0) { |
621 | rv = -EINTR; | 621 | rv = -EINTR; |
622 | rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); | 622 | rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); |
623 | RIOPreemptiveCmd(p, PortP, FCLOSE ); | 623 | RIOPreemptiveCmd(p, PortP, FCLOSE); |
624 | goto close_end; | 624 | goto close_end; |
625 | } | 625 | } |
626 | rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); | 626 | rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); |
@@ -656,14 +656,12 @@ riotclose(void *ptr) | |||
656 | goto close_end; | 656 | goto close_end; |
657 | } | 657 | } |
658 | 658 | ||
659 | |||
660 | |||
661 | /* Can't call RIOShortCommand with the port locked. */ | 659 | /* Can't call RIOShortCommand with the port locked. */ |
662 | rio_spin_unlock_irqrestore(&PortP->portSem, flags); | 660 | rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
663 | 661 | ||
664 | if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { | 662 | if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { |
665 | RIOPreemptiveCmd(p, PortP,FCLOSE); | 663 | RIOPreemptiveCmd(p, PortP, FCLOSE); |
666 | goto close_end; | 664 | goto close_end; |
667 | } | 665 | } |
668 | 666 | ||
669 | if (!deleted) | 667 | if (!deleted) |
@@ -698,7 +696,6 @@ riotclose(void *ptr) | |||
698 | */ | 696 | */ |
699 | PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW); | 697 | PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW); |
700 | 698 | ||
701 | |||
702 | #ifdef STATS | 699 | #ifdef STATS |
703 | PortP->Stat.CloseCnt++; | 700 | PortP->Stat.CloseCnt++; |
704 | #endif | 701 | #endif |
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 5bcbeb0cb9ae..f463d6baa685 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] = { | |||
161 | UPCI_AIOP_INTR_BIT_3 | 161 | UPCI_AIOP_INTR_BIT_3 |
162 | }; | 162 | }; |
163 | 163 | ||
164 | static Byte_t RData[RDATASIZE] = { | ||
165 | 0x00, 0x09, 0xf6, 0x82, | ||
166 | 0x02, 0x09, 0x86, 0xfb, | ||
167 | 0x04, 0x09, 0x00, 0x0a, | ||
168 | 0x06, 0x09, 0x01, 0x0a, | ||
169 | 0x08, 0x09, 0x8a, 0x13, | ||
170 | 0x0a, 0x09, 0xc5, 0x11, | ||
171 | 0x0c, 0x09, 0x86, 0x85, | ||
172 | 0x0e, 0x09, 0x20, 0x0a, | ||
173 | 0x10, 0x09, 0x21, 0x0a, | ||
174 | 0x12, 0x09, 0x41, 0xff, | ||
175 | 0x14, 0x09, 0x82, 0x00, | ||
176 | 0x16, 0x09, 0x82, 0x7b, | ||
177 | 0x18, 0x09, 0x8a, 0x7d, | ||
178 | 0x1a, 0x09, 0x88, 0x81, | ||
179 | 0x1c, 0x09, 0x86, 0x7a, | ||
180 | 0x1e, 0x09, 0x84, 0x81, | ||
181 | 0x20, 0x09, 0x82, 0x7c, | ||
182 | 0x22, 0x09, 0x0a, 0x0a | ||
183 | }; | ||
184 | |||
185 | static Byte_t RRegData[RREGDATASIZE] = { | ||
186 | 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ | ||
187 | 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ | ||
188 | 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ | ||
189 | 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ | ||
190 | 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ | ||
191 | 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ | ||
192 | 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ | ||
193 | 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ | ||
194 | 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ | ||
195 | 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ | ||
196 | 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ | ||
197 | 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ | ||
198 | 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ | ||
199 | }; | ||
200 | |||
201 | static CONTROLLER_T sController[CTL_SIZE] = { | ||
202 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
203 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
204 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
205 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
206 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
207 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
208 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
209 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} | ||
210 | }; | ||
211 | |||
212 | static Byte_t sBitMapClrTbl[8] = { | ||
213 | 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f | ||
214 | }; | ||
215 | |||
216 | static Byte_t sBitMapSetTbl[8] = { | ||
217 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 | ||
218 | }; | ||
219 | |||
220 | static int sClockPrescale = 0x14; | ||
221 | |||
164 | /* | 222 | /* |
165 | * Line number is the ttySIx number (x), the Minor number. We | 223 | * Line number is the ttySIx number (x), the Minor number. We |
166 | * assign them sequentially, starting at zero. The following | 224 | * assign them sequentially, starting at zero. The following |
@@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); | |||
177 | static unsigned char GetLineNumber(int ctrl, int aiop, int ch); | 235 | static unsigned char GetLineNumber(int ctrl, int aiop, int ch); |
178 | static unsigned char SetLineNumber(int ctrl, int aiop, int ch); | 236 | static unsigned char SetLineNumber(int ctrl, int aiop, int ch); |
179 | static void rp_start(struct tty_struct *tty); | 237 | static void rp_start(struct tty_struct *tty); |
238 | static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | ||
239 | int ChanNum); | ||
240 | static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); | ||
241 | static void sFlushRxFIFO(CHANNEL_T * ChP); | ||
242 | static void sFlushTxFIFO(CHANNEL_T * ChP); | ||
243 | static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
244 | static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
245 | static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
246 | static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
247 | static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); | ||
248 | static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, | ||
249 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
250 | WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, | ||
251 | int PeriodicOnly, int altChanRingIndicator, | ||
252 | int UPCIRingInd); | ||
253 | static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, | ||
254 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
255 | int IRQNum, Byte_t Frequency, int PeriodicOnly); | ||
256 | static int sReadAiopID(ByteIO_t io); | ||
257 | static int sReadAiopNumChan(WordIO_t io); | ||
180 | 258 | ||
181 | #ifdef MODULE | 259 | #ifdef MODULE |
182 | MODULE_AUTHOR("Theodore Ts'o"); | 260 | MODULE_AUTHOR("Theodore Ts'o"); |
@@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty) | |||
1798 | * init's aiopic and serial port hardware. | 1876 | * init's aiopic and serial port hardware. |
1799 | * Inputs: i is the board number (0-n) | 1877 | * Inputs: i is the board number (0-n) |
1800 | */ | 1878 | */ |
1801 | __init int register_PCI(int i, struct pci_dev *dev) | 1879 | static __init int register_PCI(int i, struct pci_dev *dev) |
1802 | { | 1880 | { |
1803 | int num_aiops, aiop, max_num_aiops, num_chan, chan; | 1881 | int num_aiops, aiop, max_num_aiops, num_chan, chan; |
1804 | unsigned int aiopio[MAX_AIOPS_PER_BOARD]; | 1882 | unsigned int aiopio[MAX_AIOPS_PER_BOARD]; |
@@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void) | |||
2453 | } | 2531 | } |
2454 | #endif | 2532 | #endif |
2455 | 2533 | ||
2456 | #ifndef TRUE | ||
2457 | #define TRUE 1 | ||
2458 | #endif | ||
2459 | |||
2460 | #ifndef FALSE | ||
2461 | #define FALSE 0 | ||
2462 | #endif | ||
2463 | |||
2464 | static Byte_t RData[RDATASIZE] = { | ||
2465 | 0x00, 0x09, 0xf6, 0x82, | ||
2466 | 0x02, 0x09, 0x86, 0xfb, | ||
2467 | 0x04, 0x09, 0x00, 0x0a, | ||
2468 | 0x06, 0x09, 0x01, 0x0a, | ||
2469 | 0x08, 0x09, 0x8a, 0x13, | ||
2470 | 0x0a, 0x09, 0xc5, 0x11, | ||
2471 | 0x0c, 0x09, 0x86, 0x85, | ||
2472 | 0x0e, 0x09, 0x20, 0x0a, | ||
2473 | 0x10, 0x09, 0x21, 0x0a, | ||
2474 | 0x12, 0x09, 0x41, 0xff, | ||
2475 | 0x14, 0x09, 0x82, 0x00, | ||
2476 | 0x16, 0x09, 0x82, 0x7b, | ||
2477 | 0x18, 0x09, 0x8a, 0x7d, | ||
2478 | 0x1a, 0x09, 0x88, 0x81, | ||
2479 | 0x1c, 0x09, 0x86, 0x7a, | ||
2480 | 0x1e, 0x09, 0x84, 0x81, | ||
2481 | 0x20, 0x09, 0x82, 0x7c, | ||
2482 | 0x22, 0x09, 0x0a, 0x0a | ||
2483 | }; | ||
2484 | |||
2485 | static Byte_t RRegData[RREGDATASIZE] = { | ||
2486 | 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ | ||
2487 | 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ | ||
2488 | 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ | ||
2489 | 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ | ||
2490 | 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ | ||
2491 | 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ | ||
2492 | 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ | ||
2493 | 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ | ||
2494 | 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ | ||
2495 | 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ | ||
2496 | 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ | ||
2497 | 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ | ||
2498 | 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ | ||
2499 | }; | ||
2500 | |||
2501 | CONTROLLER_T sController[CTL_SIZE] = { | ||
2502 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
2503 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
2504 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
2505 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
2506 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
2507 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
2508 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
2509 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} | ||
2510 | }; | ||
2511 | |||
2512 | Byte_t sBitMapClrTbl[8] = { | ||
2513 | 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f | ||
2514 | }; | ||
2515 | |||
2516 | Byte_t sBitMapSetTbl[8] = { | ||
2517 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 | ||
2518 | }; | ||
2519 | |||
2520 | int sClockPrescale = 0x14; | ||
2521 | |||
2522 | /*************************************************************************** | 2534 | /*************************************************************************** |
2523 | Function: sInitController | 2535 | Function: sInitController |
2524 | Purpose: Initialization of controller global registers and controller | 2536 | Purpose: Initialization of controller global registers and controller |
@@ -2554,22 +2566,22 @@ Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, | |||
2554 | FREQ_4HZ - 4 Hertz | 2566 | FREQ_4HZ - 4 Hertz |
2555 | If IRQNum is set to 0 the Frequency parameter is | 2567 | If IRQNum is set to 0 the Frequency parameter is |
2556 | overidden, it is forced to a value of FREQ_DIS. | 2568 | overidden, it is forced to a value of FREQ_DIS. |
2557 | int PeriodicOnly: TRUE if all interrupts except the periodic | 2569 | int PeriodicOnly: 1 if all interrupts except the periodic |
2558 | interrupt are to be blocked. | 2570 | interrupt are to be blocked. |
2559 | FALSE is both the periodic interrupt and | 2571 | 0 is both the periodic interrupt and |
2560 | other channel interrupts are allowed. | 2572 | other channel interrupts are allowed. |
2561 | If IRQNum is set to 0 the PeriodicOnly parameter is | 2573 | If IRQNum is set to 0 the PeriodicOnly parameter is |
2562 | overidden, it is forced to a value of FALSE. | 2574 | overidden, it is forced to a value of 0. |
2563 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller | 2575 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller |
2564 | initialization failed. | 2576 | initialization failed. |
2565 | 2577 | ||
2566 | Comments: | 2578 | Comments: |
2567 | If periodic interrupts are to be disabled but AIOP interrupts | 2579 | If periodic interrupts are to be disabled but AIOP interrupts |
2568 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. | 2580 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. |
2569 | 2581 | ||
2570 | If interrupts are to be completely disabled set IRQNum to 0. | 2582 | If interrupts are to be completely disabled set IRQNum to 0. |
2571 | 2583 | ||
2572 | Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an | 2584 | Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an |
2573 | invalid combination. | 2585 | invalid combination. |
2574 | 2586 | ||
2575 | This function performs initialization of global interrupt modes, | 2587 | This function performs initialization of global interrupt modes, |
@@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done. | |||
2589 | After this function all AIOPs on the controller are disabled, | 2601 | After this function all AIOPs on the controller are disabled, |
2590 | they can be enabled with sEnAiop(). | 2602 | they can be enabled with sEnAiop(). |
2591 | */ | 2603 | */ |
2592 | int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, | 2604 | static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, |
2593 | ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, | 2605 | ByteIO_t * AiopIOList, int AiopIOListSize, |
2594 | Byte_t Frequency, int PeriodicOnly) | 2606 | int IRQNum, Byte_t Frequency, int PeriodicOnly) |
2595 | { | 2607 | { |
2596 | int i; | 2608 | int i; |
2597 | ByteIO_t io; | 2609 | ByteIO_t io; |
@@ -2687,22 +2699,22 @@ Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, | |||
2687 | FREQ_4HZ - 4 Hertz | 2699 | FREQ_4HZ - 4 Hertz |
2688 | If IRQNum is set to 0 the Frequency parameter is | 2700 | If IRQNum is set to 0 the Frequency parameter is |
2689 | overidden, it is forced to a value of FREQ_DIS. | 2701 | overidden, it is forced to a value of FREQ_DIS. |
2690 | int PeriodicOnly: TRUE if all interrupts except the periodic | 2702 | int PeriodicOnly: 1 if all interrupts except the periodic |
2691 | interrupt are to be blocked. | 2703 | interrupt are to be blocked. |
2692 | FALSE is both the periodic interrupt and | 2704 | 0 is both the periodic interrupt and |
2693 | other channel interrupts are allowed. | 2705 | other channel interrupts are allowed. |
2694 | If IRQNum is set to 0 the PeriodicOnly parameter is | 2706 | If IRQNum is set to 0 the PeriodicOnly parameter is |
2695 | overidden, it is forced to a value of FALSE. | 2707 | overidden, it is forced to a value of 0. |
2696 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller | 2708 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller |
2697 | initialization failed. | 2709 | initialization failed. |
2698 | 2710 | ||
2699 | Comments: | 2711 | Comments: |
2700 | If periodic interrupts are to be disabled but AIOP interrupts | 2712 | If periodic interrupts are to be disabled but AIOP interrupts |
2701 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. | 2713 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. |
2702 | 2714 | ||
2703 | If interrupts are to be completely disabled set IRQNum to 0. | 2715 | If interrupts are to be completely disabled set IRQNum to 0. |
2704 | 2716 | ||
2705 | Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an | 2717 | Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an |
2706 | invalid combination. | 2718 | invalid combination. |
2707 | 2719 | ||
2708 | This function performs initialization of global interrupt modes, | 2720 | This function performs initialization of global interrupt modes, |
@@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done. | |||
2722 | After this function all AIOPs on the controller are disabled, | 2734 | After this function all AIOPs on the controller are disabled, |
2723 | they can be enabled with sEnAiop(). | 2735 | they can be enabled with sEnAiop(). |
2724 | */ | 2736 | */ |
2725 | int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, | 2737 | static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, |
2726 | ByteIO_t * AiopIOList, int AiopIOListSize, | 2738 | ByteIO_t * AiopIOList, int AiopIOListSize, |
2727 | WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, | 2739 | WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, |
2728 | int PeriodicOnly, int altChanRingIndicator, | 2740 | int PeriodicOnly, int altChanRingIndicator, |
2729 | int UPCIRingInd) | 2741 | int UPCIRingInd) |
2730 | { | 2742 | { |
2731 | int i; | 2743 | int i; |
2732 | ByteIO_t io; | 2744 | ByteIO_t io; |
@@ -2784,7 +2796,7 @@ Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X | |||
2784 | Warnings: No context switches are allowed while executing this function. | 2796 | Warnings: No context switches are allowed while executing this function. |
2785 | 2797 | ||
2786 | */ | 2798 | */ |
2787 | int sReadAiopID(ByteIO_t io) | 2799 | static int sReadAiopID(ByteIO_t io) |
2788 | { | 2800 | { |
2789 | Byte_t AiopID; /* ID byte from AIOP */ | 2801 | Byte_t AiopID; /* ID byte from AIOP */ |
2790 | 2802 | ||
@@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical | |||
2810 | AIOP, otherwise it is an 8 channel. | 2822 | AIOP, otherwise it is an 8 channel. |
2811 | Warnings: No context switches are allowed while executing this function. | 2823 | Warnings: No context switches are allowed while executing this function. |
2812 | */ | 2824 | */ |
2813 | int sReadAiopNumChan(WordIO_t io) | 2825 | static int sReadAiopNumChan(WordIO_t io) |
2814 | { | 2826 | { |
2815 | Word_t x; | 2827 | Word_t x; |
2816 | static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; | 2828 | static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; |
@@ -2834,15 +2846,15 @@ Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) | |||
2834 | CHANNEL_T *ChP; Ptr to channel structure | 2846 | CHANNEL_T *ChP; Ptr to channel structure |
2835 | int AiopNum; AIOP number within controller | 2847 | int AiopNum; AIOP number within controller |
2836 | int ChanNum; Channel number within AIOP | 2848 | int ChanNum; Channel number within AIOP |
2837 | Return: int: TRUE if initialization succeeded, FALSE if it fails because channel | 2849 | Return: int: 1 if initialization succeeded, 0 if it fails because channel |
2838 | number exceeds number of channels available in AIOP. | 2850 | number exceeds number of channels available in AIOP. |
2839 | Comments: This function must be called before a channel can be used. | 2851 | Comments: This function must be called before a channel can be used. |
2840 | Warnings: No range checking on any of the parameters is done. | 2852 | Warnings: No range checking on any of the parameters is done. |
2841 | 2853 | ||
2842 | No context switches are allowed while executing this function. | 2854 | No context switches are allowed while executing this function. |
2843 | */ | 2855 | */ |
2844 | int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | 2856 | static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, |
2845 | int ChanNum) | 2857 | int ChanNum) |
2846 | { | 2858 | { |
2847 | int i; | 2859 | int i; |
2848 | WordIO_t AiopIO; | 2860 | WordIO_t AiopIO; |
@@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | |||
2853 | int brd9600; | 2865 | int brd9600; |
2854 | 2866 | ||
2855 | if (ChanNum >= CtlP->AiopNumChan[AiopNum]) | 2867 | if (ChanNum >= CtlP->AiopNumChan[AiopNum]) |
2856 | return (FALSE); /* exceeds num chans in AIOP */ | 2868 | return 0; /* exceeds num chans in AIOP */ |
2857 | 2869 | ||
2858 | /* Channel, AIOP, and controller identifiers */ | 2870 | /* Channel, AIOP, and controller identifiers */ |
2859 | ChP->CtlP = CtlP; | 2871 | ChP->CtlP = CtlP; |
@@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | |||
2968 | ChP->TxPrioBuf = ChOff + _TXP_BUF; | 2980 | ChP->TxPrioBuf = ChOff + _TXP_BUF; |
2969 | sEnRxProcessor(ChP); /* start the Rx processor */ | 2981 | sEnRxProcessor(ChP); /* start the Rx processor */ |
2970 | 2982 | ||
2971 | return (TRUE); | 2983 | return 1; |
2972 | } | 2984 | } |
2973 | 2985 | ||
2974 | /*************************************************************************** | 2986 | /*************************************************************************** |
@@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function. | |||
2989 | After calling this function a delay of 4 uS is required to ensure | 3001 | After calling this function a delay of 4 uS is required to ensure |
2990 | that the receive processor is no longer processing this channel. | 3002 | that the receive processor is no longer processing this channel. |
2991 | */ | 3003 | */ |
2992 | void sStopRxProcessor(CHANNEL_T * ChP) | 3004 | static void sStopRxProcessor(CHANNEL_T * ChP) |
2993 | { | 3005 | { |
2994 | Byte_t R[4]; | 3006 | Byte_t R[4]; |
2995 | 3007 | ||
@@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO | |||
3014 | this function. | 3026 | this function. |
3015 | Warnings: No context switches are allowed while executing this function. | 3027 | Warnings: No context switches are allowed while executing this function. |
3016 | */ | 3028 | */ |
3017 | void sFlushRxFIFO(CHANNEL_T * ChP) | 3029 | static void sFlushRxFIFO(CHANNEL_T * ChP) |
3018 | { | 3030 | { |
3019 | int i; | 3031 | int i; |
3020 | Byte_t Ch; /* channel number within AIOP */ | 3032 | Byte_t Ch; /* channel number within AIOP */ |
3021 | int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ | 3033 | int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ |
3022 | 3034 | ||
3023 | if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ | 3035 | if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ |
3024 | return; /* don't need to flush */ | 3036 | return; /* don't need to flush */ |
3025 | 3037 | ||
3026 | RxFIFOEnabled = FALSE; | 3038 | RxFIFOEnabled = 0; |
3027 | if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ | 3039 | if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ |
3028 | RxFIFOEnabled = TRUE; | 3040 | RxFIFOEnabled = 1; |
3029 | sDisRxFIFO(ChP); /* disable it */ | 3041 | sDisRxFIFO(ChP); /* disable it */ |
3030 | for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ | 3042 | for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ |
3031 | sInB(ChP->IntChan); /* depends on bus i/o timing */ | 3043 | 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 | |||
3056 | this function. | 3068 | this function. |
3057 | Warnings: No context switches are allowed while executing this function. | 3069 | Warnings: No context switches are allowed while executing this function. |
3058 | */ | 3070 | */ |
3059 | void sFlushTxFIFO(CHANNEL_T * ChP) | 3071 | static void sFlushTxFIFO(CHANNEL_T * ChP) |
3060 | { | 3072 | { |
3061 | int i; | 3073 | int i; |
3062 | Byte_t Ch; /* channel number within AIOP */ | 3074 | Byte_t Ch; /* channel number within AIOP */ |
3063 | int TxEnabled; /* TRUE if transmitter enabled */ | 3075 | int TxEnabled; /* 1 if transmitter enabled */ |
3064 | 3076 | ||
3065 | if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ | 3077 | if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ |
3066 | return; /* don't need to flush */ | 3078 | return; /* don't need to flush */ |
3067 | 3079 | ||
3068 | TxEnabled = FALSE; | 3080 | TxEnabled = 0; |
3069 | if (ChP->TxControl[3] & TX_ENABLE) { | 3081 | if (ChP->TxControl[3] & TX_ENABLE) { |
3070 | TxEnabled = TRUE; | 3082 | TxEnabled = 1; |
3071 | sDisTransmit(ChP); /* disable transmitter */ | 3083 | sDisTransmit(ChP); /* disable transmitter */ |
3072 | } | 3084 | } |
3073 | sStopRxProcessor(ChP); /* stop Rx processor */ | 3085 | sStopRxProcessor(ChP); /* stop Rx processor */ |
@@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO. | |||
3096 | 3108 | ||
3097 | Warnings: No context switches are allowed while executing this function. | 3109 | Warnings: No context switches are allowed while executing this function. |
3098 | */ | 3110 | */ |
3099 | int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) | 3111 | static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) |
3100 | { | 3112 | { |
3101 | Byte_t DWBuf[4]; /* buffer for double word writes */ | 3113 | Byte_t DWBuf[4]; /* buffer for double word writes */ |
3102 | Word_t *WordPtr; /* must be far because Win SS != DS */ | 3114 | 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 | |||
3158 | enable channel interrupts. This would allow the global interrupt | 3170 | enable channel interrupts. This would allow the global interrupt |
3159 | status register to be used to determine which AIOPs need service. | 3171 | status register to be used to determine which AIOPs need service. |
3160 | */ | 3172 | */ |
3161 | void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) | 3173 | static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) |
3162 | { | 3174 | { |
3163 | Byte_t Mask; /* Interrupt Mask Register */ | 3175 | Byte_t Mask; /* Interrupt Mask Register */ |
3164 | 3176 | ||
@@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be | |||
3202 | this channel's bit from being set in the AIOP's Interrupt Channel | 3214 | this channel's bit from being set in the AIOP's Interrupt Channel |
3203 | Register. | 3215 | Register. |
3204 | */ | 3216 | */ |
3205 | void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) | 3217 | static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) |
3206 | { | 3218 | { |
3207 | Byte_t Mask; /* Interrupt Mask Register */ | 3219 | Byte_t Mask; /* Interrupt Mask Register */ |
3208 | 3220 | ||
@@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) | |||
3218 | } | 3230 | } |
3219 | } | 3231 | } |
3220 | 3232 | ||
3221 | void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) | 3233 | static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) |
3222 | { | 3234 | { |
3223 | sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); | 3235 | sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); |
3224 | } | 3236 | } |
@@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) | |||
3227 | * Not an official SSCI function, but how to reset RocketModems. | 3239 | * Not an official SSCI function, but how to reset RocketModems. |
3228 | * ISA bus version | 3240 | * ISA bus version |
3229 | */ | 3241 | */ |
3230 | void sModemReset(CONTROLLER_T * CtlP, int chan, int on) | 3242 | static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) |
3231 | { | 3243 | { |
3232 | ByteIO_t addr; | 3244 | ByteIO_t addr; |
3233 | Byte_t val; | 3245 | Byte_t val; |
@@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on) | |||
3252 | * Not an official SSCI function, but how to reset RocketModems. | 3264 | * Not an official SSCI function, but how to reset RocketModems. |
3253 | * PCI bus version | 3265 | * PCI bus version |
3254 | */ | 3266 | */ |
3255 | void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) | 3267 | static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) |
3256 | { | 3268 | { |
3257 | ByteIO_t addr; | 3269 | ByteIO_t addr; |
3258 | 3270 | ||
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 802687290ee1..3a8bcc85bc14 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 | |||
1130 | */ | 1130 | */ |
1131 | #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) | 1131 | #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) |
1132 | 1132 | ||
1133 | int sInitController(CONTROLLER_T * CtlP, | ||
1134 | int CtlNum, | ||
1135 | ByteIO_t MudbacIO, | ||
1136 | ByteIO_t * AiopIOList, | ||
1137 | int AiopIOListSize, | ||
1138 | int IRQNum, Byte_t Frequency, int PeriodicOnly); | ||
1139 | |||
1140 | int sPCIInitController(CONTROLLER_T * CtlP, | ||
1141 | int CtlNum, | ||
1142 | ByteIO_t * AiopIOList, | ||
1143 | int AiopIOListSize, | ||
1144 | WordIO_t ConfigIO, | ||
1145 | int IRQNum, | ||
1146 | Byte_t Frequency, | ||
1147 | int PeriodicOnly, | ||
1148 | int altChanRingIndicator, int UPCIRingInd); | ||
1149 | |||
1150 | int sReadAiopID(ByteIO_t io); | ||
1151 | int sReadAiopNumChan(WordIO_t io); | ||
1152 | int sInitChan(CONTROLLER_T * CtlP, | ||
1153 | CHANNEL_T * ChP, int AiopNum, int ChanNum); | ||
1154 | Byte_t sGetRxErrStatus(CHANNEL_T * ChP); | ||
1155 | void sStopRxProcessor(CHANNEL_T * ChP); | ||
1156 | void sStopSWInFlowCtl(CHANNEL_T * ChP); | ||
1157 | void sFlushRxFIFO(CHANNEL_T * ChP); | ||
1158 | void sFlushTxFIFO(CHANNEL_T * ChP); | ||
1159 | int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); | ||
1160 | void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
1161 | void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
1162 | void sModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
1163 | void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
1164 | void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); | ||
1165 | |||
1166 | extern Byte_t R[RDATASIZE]; | ||
1167 | extern CONTROLLER_T sController[CTL_SIZE]; | ||
1168 | extern Byte_t sIRQMap[16]; | ||
1169 | extern Byte_t sBitMapClrTbl[8]; | ||
1170 | extern Byte_t sBitMapSetTbl[8]; | ||
1171 | extern int sClockPrescale; | ||
1172 | |||
1173 | /* | 1133 | /* |
1174 | * Begin Linux specific definitions for the Rocketport driver | 1134 | * Begin Linux specific definitions for the Rocketport driver |
1175 | * | 1135 | * |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index f59f7cbd525b..af79805b5576 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/vt_kern.h> | 36 | #include <linux/vt_kern.h> |
37 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
38 | #include <linux/kexec.h> | ||
38 | 39 | ||
39 | #include <asm/ptrace.h> | 40 | #include <asm/ptrace.h> |
40 | 41 | ||
@@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = { | |||
94 | }; | 95 | }; |
95 | #endif /* CONFIG_VT */ | 96 | #endif /* CONFIG_VT */ |
96 | 97 | ||
98 | #ifdef CONFIG_KEXEC | ||
99 | /* crashdump sysrq handler */ | ||
100 | static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, | ||
101 | struct tty_struct *tty) | ||
102 | { | ||
103 | crash_kexec(pt_regs); | ||
104 | } | ||
105 | static struct sysrq_key_op sysrq_crashdump_op = { | ||
106 | .handler = sysrq_handle_crashdump, | ||
107 | .help_msg = "Crashdump", | ||
108 | .action_msg = "Trigger a crashdump", | ||
109 | .enable_mask = SYSRQ_ENABLE_DUMP, | ||
110 | }; | ||
111 | #endif | ||
112 | |||
97 | /* reboot sysrq handler */ | 113 | /* reboot sysrq handler */ |
98 | static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, | 114 | static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, |
99 | struct tty_struct *tty) | 115 | struct tty_struct *tty) |
@@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { | |||
273 | it is handled specially on the sparc | 289 | it is handled specially on the sparc |
274 | and will never arrive */ | 290 | and will never arrive */ |
275 | /* b */ &sysrq_reboot_op, | 291 | /* b */ &sysrq_reboot_op, |
276 | /* c */ NULL, | 292 | #ifdef CONFIG_KEXEC |
277 | /* d */ NULL, | 293 | /* c */ &sysrq_crashdump_op, |
294 | #else | ||
295 | /* c */ NULL, | ||
296 | #endif | ||
297 | /* d */ NULL, | ||
278 | /* e */ &sysrq_term_op, | 298 | /* e */ &sysrq_term_op, |
279 | /* f */ &sysrq_moom_op, | 299 | /* f */ &sysrq_moom_op, |
280 | /* g */ NULL, | 300 | /* g */ NULL, |
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 58e21fe44262..0c6f521abd0e 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c | |||
@@ -73,16 +73,20 @@ | |||
73 | 73 | ||
74 | #define TOSH_MINOR_DEV 181 | 74 | #define TOSH_MINOR_DEV 181 |
75 | 75 | ||
76 | static int tosh_id = 0x0000; | 76 | MODULE_LICENSE("GPL"); |
77 | static int tosh_bios = 0x0000; | 77 | MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); |
78 | static int tosh_date = 0x0000; | 78 | MODULE_DESCRIPTION("Toshiba laptop SMM driver"); |
79 | static int tosh_sci = 0x0000; | 79 | MODULE_SUPPORTED_DEVICE("toshiba"); |
80 | static int tosh_fan = 0; | ||
81 | |||
82 | static int tosh_fn = 0; | ||
83 | 80 | ||
84 | module_param(tosh_fn, int, 0); | 81 | static int tosh_fn; |
82 | module_param_named(fn, tosh_fn, int, 0); | ||
83 | MODULE_PARM_DESC(fn, "User specified Fn key detection port"); | ||
85 | 84 | ||
85 | static int tosh_id; | ||
86 | static int tosh_bios; | ||
87 | static int tosh_date; | ||
88 | static int tosh_sci; | ||
89 | static int tosh_fan; | ||
86 | 90 | ||
87 | static int tosh_ioctl(struct inode *, struct file *, unsigned int, | 91 | static int tosh_ioctl(struct inode *, struct file *, unsigned int, |
88 | unsigned long); | 92 | unsigned long); |
@@ -359,7 +363,7 @@ static int tosh_get_machine_id(void) | |||
359 | unsigned long address; | 363 | unsigned long address; |
360 | 364 | ||
361 | id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa)); | 365 | id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa)); |
362 | 366 | ||
363 | /* do we have a SCTTable machine identication number on our hands */ | 367 | /* do we have a SCTTable machine identication number on our hands */ |
364 | 368 | ||
365 | if (id==0xfc2f) { | 369 | if (id==0xfc2f) { |
@@ -424,7 +428,7 @@ static int tosh_probe(void) | |||
424 | } | 428 | } |
425 | 429 | ||
426 | /* call the Toshiba SCI support check routine */ | 430 | /* call the Toshiba SCI support check routine */ |
427 | 431 | ||
428 | regs.eax = 0xf0f0; | 432 | regs.eax = 0xf0f0; |
429 | regs.ebx = 0x0000; | 433 | regs.ebx = 0x0000; |
430 | regs.ecx = 0x0000; | 434 | regs.ecx = 0x0000; |
@@ -440,7 +444,7 @@ static int tosh_probe(void) | |||
440 | /* if we get this far then we are running on a Toshiba (probably)! */ | 444 | /* if we get this far then we are running on a Toshiba (probably)! */ |
441 | 445 | ||
442 | tosh_sci = regs.edx & 0xffff; | 446 | tosh_sci = regs.edx & 0xffff; |
443 | 447 | ||
444 | /* next get the machine ID of the current laptop */ | 448 | /* next get the machine ID of the current laptop */ |
445 | 449 | ||
446 | tosh_id = tosh_get_machine_id(); | 450 | tosh_id = tosh_get_machine_id(); |
@@ -475,16 +479,15 @@ static int tosh_probe(void) | |||
475 | return 0; | 479 | return 0; |
476 | } | 480 | } |
477 | 481 | ||
478 | int __init tosh_init(void) | 482 | static int __init toshiba_init(void) |
479 | { | 483 | { |
480 | int retval; | 484 | int retval; |
481 | /* are we running on a Toshiba laptop */ | 485 | /* are we running on a Toshiba laptop */ |
482 | 486 | ||
483 | if (tosh_probe()!=0) | 487 | if (tosh_probe()) |
484 | return -EIO; | 488 | return -ENODEV; |
485 | 489 | ||
486 | printk(KERN_INFO "Toshiba System Managment Mode driver v" | 490 | printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n"); |
487 | TOSH_VERSION"\n"); | ||
488 | 491 | ||
489 | /* set the port to use for Fn status if not specified as a parameter */ | 492 | /* set the port to use for Fn status if not specified as a parameter */ |
490 | if (tosh_fn==0x00) | 493 | if (tosh_fn==0x00) |
@@ -492,12 +495,12 @@ int __init tosh_init(void) | |||
492 | 495 | ||
493 | /* register the device file */ | 496 | /* register the device file */ |
494 | retval = misc_register(&tosh_device); | 497 | retval = misc_register(&tosh_device); |
495 | if(retval < 0) | 498 | if (retval < 0) |
496 | return retval; | 499 | return retval; |
497 | 500 | ||
498 | #ifdef CONFIG_PROC_FS | 501 | #ifdef CONFIG_PROC_FS |
499 | /* register the proc entry */ | 502 | /* register the proc entry */ |
500 | if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){ | 503 | if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) { |
501 | misc_deregister(&tosh_device); | 504 | misc_deregister(&tosh_device); |
502 | return -ENOMEM; | 505 | return -ENOMEM; |
503 | } | 506 | } |
@@ -506,27 +509,12 @@ int __init tosh_init(void) | |||
506 | return 0; | 509 | return 0; |
507 | } | 510 | } |
508 | 511 | ||
509 | #ifdef MODULE | 512 | static void __exit toshiba_exit(void) |
510 | int init_module(void) | ||
511 | { | ||
512 | return tosh_init(); | ||
513 | } | ||
514 | |||
515 | void cleanup_module(void) | ||
516 | { | 513 | { |
517 | /* remove the proc entry */ | ||
518 | |||
519 | remove_proc_entry("toshiba", NULL); | 514 | remove_proc_entry("toshiba", NULL); |
520 | |||
521 | /* unregister the device file */ | ||
522 | |||
523 | misc_deregister(&tosh_device); | 515 | misc_deregister(&tosh_device); |
524 | } | 516 | } |
525 | #endif | ||
526 | 517 | ||
527 | MODULE_LICENSE("GPL"); | 518 | module_init(toshiba_init); |
528 | MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port"); | 519 | module_exit(toshiba_exit); |
529 | MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); | ||
530 | MODULE_DESCRIPTION("Toshiba laptop SMM driver"); | ||
531 | MODULE_SUPPORTED_DEVICE("toshiba"); | ||
532 | 520 | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 8ce508b29865..854475c54f0e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -19,7 +19,7 @@ | |||
19 | * | 19 | * |
20 | * Note, the TPM chip is not interrupt driven (only polling) | 20 | * Note, the TPM chip is not interrupt driven (only polling) |
21 | * and can have very long timeouts (minutes!). Hence the unusual | 21 | * and can have very long timeouts (minutes!). Hence the unusual |
22 | * calls to schedule_timeout. | 22 | * calls to msleep. |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
@@ -28,19 +28,16 @@ | |||
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include "tpm.h" | 29 | #include "tpm.h" |
30 | 30 | ||
31 | #define TPM_MINOR 224 /* officially assigned */ | 31 | enum tpm_const { |
32 | 32 | TPM_MINOR = 224, /* officially assigned */ | |
33 | #define TPM_BUFSIZE 2048 | 33 | TPM_BUFSIZE = 2048, |
34 | 34 | TPM_NUM_DEVICES = 256, | |
35 | /* PCI configuration addresses */ | 35 | TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) |
36 | #define PCI_GEN_PMCON_1 0xA0 | 36 | }; |
37 | #define PCI_GEN1_DEC 0xE4 | ||
38 | #define PCI_LPC_EN 0xE6 | ||
39 | #define PCI_GEN2_DEC 0xEC | ||
40 | 37 | ||
41 | static LIST_HEAD(tpm_chip_list); | 38 | static LIST_HEAD(tpm_chip_list); |
42 | static DEFINE_SPINLOCK(driver_lock); | 39 | static DEFINE_SPINLOCK(driver_lock); |
43 | static int dev_mask[32]; | 40 | static int dev_mask[TPM_NUM_MASK_ENTRIES]; |
44 | 41 | ||
45 | static void user_reader_timeout(unsigned long ptr) | 42 | static void user_reader_timeout(unsigned long ptr) |
46 | { | 43 | { |
@@ -52,92 +49,17 @@ static void user_reader_timeout(unsigned long ptr) | |||
52 | up(&chip->buffer_mutex); | 49 | up(&chip->buffer_mutex); |
53 | } | 50 | } |
54 | 51 | ||
55 | void tpm_time_expired(unsigned long ptr) | ||
56 | { | ||
57 | int *exp = (int *) ptr; | ||
58 | *exp = 1; | ||
59 | } | ||
60 | |||
61 | EXPORT_SYMBOL_GPL(tpm_time_expired); | ||
62 | |||
63 | /* | ||
64 | * Initialize the LPC bus and enable the TPM ports | ||
65 | */ | ||
66 | int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base) | ||
67 | { | ||
68 | u32 lpcenable, tmp; | ||
69 | int is_lpcm = 0; | ||
70 | |||
71 | switch (pci_dev->vendor) { | ||
72 | case PCI_VENDOR_ID_INTEL: | ||
73 | switch (pci_dev->device) { | ||
74 | case PCI_DEVICE_ID_INTEL_82801CA_12: | ||
75 | case PCI_DEVICE_ID_INTEL_82801DB_12: | ||
76 | is_lpcm = 1; | ||
77 | break; | ||
78 | } | ||
79 | /* init ICH (enable LPC) */ | ||
80 | pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable); | ||
81 | lpcenable |= 0x20000000; | ||
82 | pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable); | ||
83 | |||
84 | if (is_lpcm) { | ||
85 | pci_read_config_dword(pci_dev, PCI_GEN1_DEC, | ||
86 | &lpcenable); | ||
87 | if ((lpcenable & 0x20000000) == 0) { | ||
88 | dev_err(&pci_dev->dev, | ||
89 | "cannot enable LPC\n"); | ||
90 | return -ENODEV; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* initialize TPM registers */ | ||
95 | pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp); | ||
96 | |||
97 | if (!is_lpcm) | ||
98 | tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0); | ||
99 | else | ||
100 | tmp = | ||
101 | (tmp & 0xFFFF0000) | (base & 0xFFF0) | | ||
102 | 0x00000001; | ||
103 | |||
104 | pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp); | ||
105 | |||
106 | if (is_lpcm) { | ||
107 | pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1, | ||
108 | &tmp); | ||
109 | tmp |= 0x00000004; /* enable CLKRUN */ | ||
110 | pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1, | ||
111 | tmp); | ||
112 | } | ||
113 | tpm_write_index(0x0D, 0x55); /* unlock 4F */ | ||
114 | tpm_write_index(0x0A, 0x00); /* int disable */ | ||
115 | tpm_write_index(0x08, base); /* base addr lo */ | ||
116 | tpm_write_index(0x09, (base & 0xFF00) >> 8); /* base addr hi */ | ||
117 | tpm_write_index(0x0D, 0xAA); /* lock 4F */ | ||
118 | break; | ||
119 | case PCI_VENDOR_ID_AMD: | ||
120 | /* nothing yet */ | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | EXPORT_SYMBOL_GPL(tpm_lpc_bus_init); | ||
128 | |||
129 | /* | 52 | /* |
130 | * Internal kernel interface to transmit TPM commands | 53 | * Internal kernel interface to transmit TPM commands |
131 | */ | 54 | */ |
132 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 55 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |
133 | size_t bufsiz) | 56 | size_t bufsiz) |
134 | { | 57 | { |
135 | ssize_t len; | 58 | ssize_t rc; |
136 | u32 count; | 59 | u32 count; |
137 | __be32 *native_size; | 60 | unsigned long stop; |
138 | 61 | ||
139 | native_size = (__force __be32 *) (buf + 2); | 62 | count = be32_to_cpu(*((__be32 *) (buf + 2))); |
140 | count = be32_to_cpu(*native_size); | ||
141 | 63 | ||
142 | if (count == 0) | 64 | if (count == 0) |
143 | return -ENODATA; | 65 | return -ENODATA; |
@@ -149,53 +71,49 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
149 | 71 | ||
150 | down(&chip->tpm_mutex); | 72 | down(&chip->tpm_mutex); |
151 | 73 | ||
152 | if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { | 74 | if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { |
153 | dev_err(&chip->pci_dev->dev, | 75 | dev_err(&chip->pci_dev->dev, |
154 | "tpm_transmit: tpm_send: error %zd\n", len); | 76 | "tpm_transmit: tpm_send: error %zd\n", rc); |
155 | return len; | 77 | goto out; |
156 | } | 78 | } |
157 | 79 | ||
158 | down(&chip->timer_manipulation_mutex); | 80 | stop = jiffies + 2 * 60 * HZ; |
159 | chip->time_expired = 0; | ||
160 | init_timer(&chip->device_timer); | ||
161 | chip->device_timer.function = tpm_time_expired; | ||
162 | chip->device_timer.expires = jiffies + 2 * 60 * HZ; | ||
163 | chip->device_timer.data = (unsigned long) &chip->time_expired; | ||
164 | add_timer(&chip->device_timer); | ||
165 | up(&chip->timer_manipulation_mutex); | ||
166 | |||
167 | do { | 81 | do { |
168 | u8 status = inb(chip->vendor->base + 1); | 82 | u8 status = inb(chip->vendor->base + 1); |
169 | if ((status & chip->vendor->req_complete_mask) == | 83 | if ((status & chip->vendor->req_complete_mask) == |
170 | chip->vendor->req_complete_val) { | 84 | chip->vendor->req_complete_val) { |
171 | down(&chip->timer_manipulation_mutex); | ||
172 | del_singleshot_timer_sync(&chip->device_timer); | ||
173 | up(&chip->timer_manipulation_mutex); | ||
174 | goto out_recv; | 85 | goto out_recv; |
175 | } | 86 | } |
176 | set_current_state(TASK_UNINTERRUPTIBLE); | 87 | |
177 | schedule_timeout(TPM_TIMEOUT); | 88 | if ((status == chip->vendor->req_canceled)) { |
89 | dev_err(&chip->pci_dev->dev, "Operation Canceled\n"); | ||
90 | rc = -ECANCELED; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | msleep(TPM_TIMEOUT); /* CHECK */ | ||
178 | rmb(); | 95 | rmb(); |
179 | } while (!chip->time_expired); | 96 | } while (time_before(jiffies, stop)); |
180 | 97 | ||
181 | 98 | ||
182 | chip->vendor->cancel(chip); | 99 | chip->vendor->cancel(chip); |
183 | dev_err(&chip->pci_dev->dev, "Time expired\n"); | 100 | dev_err(&chip->pci_dev->dev, "Operation Timed out\n"); |
184 | up(&chip->tpm_mutex); | 101 | rc = -ETIME; |
185 | return -EIO; | 102 | goto out; |
186 | 103 | ||
187 | out_recv: | 104 | out_recv: |
188 | len = chip->vendor->recv(chip, (u8 *) buf, bufsiz); | 105 | rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); |
189 | if (len < 0) | 106 | if (rc < 0) |
190 | dev_err(&chip->pci_dev->dev, | 107 | dev_err(&chip->pci_dev->dev, |
191 | "tpm_transmit: tpm_recv: error %zd\n", len); | 108 | "tpm_transmit: tpm_recv: error %zd\n", rc); |
109 | out: | ||
192 | up(&chip->tpm_mutex); | 110 | up(&chip->tpm_mutex); |
193 | return len; | 111 | return rc; |
194 | } | 112 | } |
195 | 113 | ||
196 | #define TPM_DIGEST_SIZE 20 | 114 | #define TPM_DIGEST_SIZE 20 |
197 | #define CAP_PCR_RESULT_SIZE 18 | 115 | #define CAP_PCR_RESULT_SIZE 18 |
198 | static u8 cap_pcr[] = { | 116 | static const u8 cap_pcr[] = { |
199 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 117 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
200 | 0, 0, 0, 22, /* length */ | 118 | 0, 0, 0, 22, /* length */ |
201 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 119 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
@@ -205,75 +123,94 @@ static u8 cap_pcr[] = { | |||
205 | }; | 123 | }; |
206 | 124 | ||
207 | #define READ_PCR_RESULT_SIZE 30 | 125 | #define READ_PCR_RESULT_SIZE 30 |
208 | static u8 pcrread[] = { | 126 | static const u8 pcrread[] = { |
209 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 127 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
210 | 0, 0, 0, 14, /* length */ | 128 | 0, 0, 0, 14, /* length */ |
211 | 0, 0, 0, 21, /* TPM_ORD_PcrRead */ | 129 | 0, 0, 0, 21, /* TPM_ORD_PcrRead */ |
212 | 0, 0, 0, 0 /* PCR index */ | 130 | 0, 0, 0, 0 /* PCR index */ |
213 | }; | 131 | }; |
214 | 132 | ||
215 | static ssize_t show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) | 133 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
134 | char *buf) | ||
216 | { | 135 | { |
217 | u8 data[READ_PCR_RESULT_SIZE]; | 136 | u8 data[READ_PCR_RESULT_SIZE]; |
218 | ssize_t len; | 137 | ssize_t len; |
219 | int i, j, index, num_pcrs; | 138 | int i, j, num_pcrs; |
139 | __be32 index; | ||
220 | char *str = buf; | 140 | char *str = buf; |
221 | 141 | ||
222 | struct tpm_chip *chip = | 142 | struct tpm_chip *chip = |
223 | pci_get_drvdata(container_of(dev, struct pci_dev, dev)); | 143 | pci_get_drvdata(to_pci_dev(dev)); |
224 | if (chip == NULL) | 144 | if (chip == NULL) |
225 | return -ENODEV; | 145 | return -ENODEV; |
226 | 146 | ||
227 | memcpy(data, cap_pcr, sizeof(cap_pcr)); | 147 | memcpy(data, cap_pcr, sizeof(cap_pcr)); |
228 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 148 | if ((len = tpm_transmit(chip, data, sizeof(data))) |
229 | < CAP_PCR_RESULT_SIZE) | 149 | < CAP_PCR_RESULT_SIZE) { |
230 | return len; | 150 | dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " |
151 | "attempting to determine the number of PCRS\n", | ||
152 | be32_to_cpu(*((__be32 *) (data + 6)))); | ||
153 | return 0; | ||
154 | } | ||
231 | 155 | ||
232 | num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14))); | 156 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); |
233 | 157 | ||
234 | for (i = 0; i < num_pcrs; i++) { | 158 | for (i = 0; i < num_pcrs; i++) { |
235 | memcpy(data, pcrread, sizeof(pcrread)); | 159 | memcpy(data, pcrread, sizeof(pcrread)); |
236 | index = cpu_to_be32(i); | 160 | index = cpu_to_be32(i); |
237 | memcpy(data + 10, &index, 4); | 161 | memcpy(data + 10, &index, 4); |
238 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 162 | if ((len = tpm_transmit(chip, data, sizeof(data))) |
239 | < READ_PCR_RESULT_SIZE) | 163 | < READ_PCR_RESULT_SIZE){ |
240 | return len; | 164 | dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred" |
165 | " attempting to read PCR %d of %d\n", | ||
166 | be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs); | ||
167 | goto out; | ||
168 | } | ||
241 | str += sprintf(str, "PCR-%02d: ", i); | 169 | str += sprintf(str, "PCR-%02d: ", i); |
242 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 170 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
243 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 171 | str += sprintf(str, "%02X ", *(data + 10 + j)); |
244 | str += sprintf(str, "\n"); | 172 | str += sprintf(str, "\n"); |
245 | } | 173 | } |
174 | out: | ||
246 | return str - buf; | 175 | return str - buf; |
247 | } | 176 | } |
248 | 177 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | |
249 | static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL); | ||
250 | 178 | ||
251 | #define READ_PUBEK_RESULT_SIZE 314 | 179 | #define READ_PUBEK_RESULT_SIZE 314 |
252 | static u8 readpubek[] = { | 180 | static const u8 readpubek[] = { |
253 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 181 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
254 | 0, 0, 0, 30, /* length */ | 182 | 0, 0, 0, 30, /* length */ |
255 | 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ | 183 | 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ |
256 | }; | 184 | }; |
257 | 185 | ||
258 | static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, char *buf) | 186 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, |
187 | char *buf) | ||
259 | { | 188 | { |
260 | u8 data[READ_PUBEK_RESULT_SIZE]; | 189 | u8 *data; |
261 | ssize_t len; | 190 | ssize_t len; |
262 | __be32 *native_val; | 191 | int i, rc; |
263 | int i; | ||
264 | char *str = buf; | 192 | char *str = buf; |
265 | 193 | ||
266 | struct tpm_chip *chip = | 194 | struct tpm_chip *chip = |
267 | pci_get_drvdata(container_of(dev, struct pci_dev, dev)); | 195 | pci_get_drvdata(to_pci_dev(dev)); |
268 | if (chip == NULL) | 196 | if (chip == NULL) |
269 | return -ENODEV; | 197 | return -ENODEV; |
270 | 198 | ||
199 | data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); | ||
200 | if (!data) | ||
201 | return -ENOMEM; | ||
202 | |||
271 | memcpy(data, readpubek, sizeof(readpubek)); | 203 | memcpy(data, readpubek, sizeof(readpubek)); |
272 | memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ | 204 | memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ |
273 | 205 | ||
274 | if ((len = tpm_transmit(chip, data, sizeof(data))) < | 206 | if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < |
275 | READ_PUBEK_RESULT_SIZE) | 207 | READ_PUBEK_RESULT_SIZE) { |
276 | return len; | 208 | dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " |
209 | "attempting to read the PUBEK\n", | ||
210 | be32_to_cpu(*((__be32 *) (data + 6)))); | ||
211 | rc = 0; | ||
212 | goto out; | ||
213 | } | ||
277 | 214 | ||
278 | /* | 215 | /* |
279 | ignore header 10 bytes | 216 | ignore header 10 bytes |
@@ -286,8 +223,6 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha | |||
286 | ignore checksum 20 bytes | 223 | ignore checksum 20 bytes |
287 | */ | 224 | */ |
288 | 225 | ||
289 | native_val = (__force __be32 *) (data + 34); | ||
290 | |||
291 | str += | 226 | str += |
292 | sprintf(str, | 227 | sprintf(str, |
293 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 228 | "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 | |||
298 | data[15], data[16], data[17], data[22], data[23], | 233 | data[15], data[16], data[17], data[22], data[23], |
299 | data[24], data[25], data[26], data[27], data[28], | 234 | data[24], data[25], data[26], data[27], data[28], |
300 | data[29], data[30], data[31], data[32], data[33], | 235 | data[29], data[30], data[31], data[32], data[33], |
301 | be32_to_cpu(*native_val) | 236 | be32_to_cpu(*((__be32 *) (data + 34)))); |
302 | ); | ||
303 | 237 | ||
304 | for (i = 0; i < 256; i++) { | 238 | for (i = 0; i < 256; i++) { |
305 | str += sprintf(str, "%02X ", data[i + 39]); | 239 | str += sprintf(str, "%02X ", data[i + 38]); |
306 | if ((i + 1) % 16 == 0) | 240 | if ((i + 1) % 16 == 0) |
307 | str += sprintf(str, "\n"); | 241 | str += sprintf(str, "\n"); |
308 | } | 242 | } |
309 | return str - buf; | 243 | rc = str - buf; |
244 | out: | ||
245 | kfree(data); | ||
246 | return rc; | ||
310 | } | 247 | } |
311 | 248 | ||
312 | static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL); | 249 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
313 | 250 | ||
314 | #define CAP_VER_RESULT_SIZE 18 | 251 | #define CAP_VER_RESULT_SIZE 18 |
315 | static u8 cap_version[] = { | 252 | static const u8 cap_version[] = { |
316 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 253 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
317 | 0, 0, 0, 18, /* length */ | 254 | 0, 0, 0, 18, /* length */ |
318 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 255 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
@@ -321,7 +258,7 @@ static u8 cap_version[] = { | |||
321 | }; | 258 | }; |
322 | 259 | ||
323 | #define CAP_MANUFACTURER_RESULT_SIZE 18 | 260 | #define CAP_MANUFACTURER_RESULT_SIZE 18 |
324 | static u8 cap_manufacturer[] = { | 261 | static const u8 cap_manufacturer[] = { |
325 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 262 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
326 | 0, 0, 0, 22, /* length */ | 263 | 0, 0, 0, 22, /* length */ |
327 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 264 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
@@ -330,14 +267,15 @@ static u8 cap_manufacturer[] = { | |||
330 | 0, 0, 1, 3 | 267 | 0, 0, 1, 3 |
331 | }; | 268 | }; |
332 | 269 | ||
333 | static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char *buf) | 270 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
271 | char *buf) | ||
334 | { | 272 | { |
335 | u8 data[READ_PUBEK_RESULT_SIZE]; | 273 | u8 data[sizeof(cap_manufacturer)]; |
336 | ssize_t len; | 274 | ssize_t len; |
337 | char *str = buf; | 275 | char *str = buf; |
338 | 276 | ||
339 | struct tpm_chip *chip = | 277 | struct tpm_chip *chip = |
340 | pci_get_drvdata(container_of(dev, struct pci_dev, dev)); | 278 | pci_get_drvdata(to_pci_dev(dev)); |
341 | if (chip == NULL) | 279 | if (chip == NULL) |
342 | return -ENODEV; | 280 | return -ENODEV; |
343 | 281 | ||
@@ -348,7 +286,7 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char | |||
348 | return len; | 286 | return len; |
349 | 287 | ||
350 | str += sprintf(str, "Manufacturer: 0x%x\n", | 288 | str += sprintf(str, "Manufacturer: 0x%x\n", |
351 | be32_to_cpu(*(data + 14))); | 289 | be32_to_cpu(*((__be32 *) (data + 14)))); |
352 | 290 | ||
353 | memcpy(data, cap_version, sizeof(cap_version)); | 291 | memcpy(data, cap_version, sizeof(cap_version)); |
354 | 292 | ||
@@ -363,8 +301,20 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char | |||
363 | 301 | ||
364 | return str - buf; | 302 | return str - buf; |
365 | } | 303 | } |
304 | EXPORT_SYMBOL_GPL(tpm_show_caps); | ||
305 | |||
306 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | ||
307 | const char *buf, size_t count) | ||
308 | { | ||
309 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
310 | if (chip == NULL) | ||
311 | return 0; | ||
312 | |||
313 | chip->vendor->cancel(chip); | ||
314 | return count; | ||
315 | } | ||
316 | EXPORT_SYMBOL_GPL(tpm_store_cancel); | ||
366 | 317 | ||
367 | static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL); | ||
368 | 318 | ||
369 | /* | 319 | /* |
370 | * Device file system interface to the TPM | 320 | * Device file system interface to the TPM |
@@ -422,24 +372,15 @@ EXPORT_SYMBOL_GPL(tpm_open); | |||
422 | int tpm_release(struct inode *inode, struct file *file) | 372 | int tpm_release(struct inode *inode, struct file *file) |
423 | { | 373 | { |
424 | struct tpm_chip *chip = file->private_data; | 374 | struct tpm_chip *chip = file->private_data; |
425 | |||
426 | file->private_data = NULL; | ||
427 | 375 | ||
428 | spin_lock(&driver_lock); | 376 | spin_lock(&driver_lock); |
377 | file->private_data = NULL; | ||
429 | chip->num_opens--; | 378 | chip->num_opens--; |
430 | spin_unlock(&driver_lock); | 379 | del_singleshot_timer_sync(&chip->user_read_timer); |
431 | |||
432 | down(&chip->timer_manipulation_mutex); | ||
433 | if (timer_pending(&chip->user_read_timer)) | ||
434 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
435 | else if (timer_pending(&chip->device_timer)) | ||
436 | del_singleshot_timer_sync(&chip->device_timer); | ||
437 | up(&chip->timer_manipulation_mutex); | ||
438 | |||
439 | kfree(chip->data_buffer); | ||
440 | atomic_set(&chip->data_pending, 0); | 380 | atomic_set(&chip->data_pending, 0); |
441 | |||
442 | pci_dev_put(chip->pci_dev); | 381 | pci_dev_put(chip->pci_dev); |
382 | kfree(chip->data_buffer); | ||
383 | spin_unlock(&driver_lock); | ||
443 | return 0; | 384 | return 0; |
444 | } | 385 | } |
445 | 386 | ||
@@ -453,10 +394,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf, | |||
453 | 394 | ||
454 | /* cannot perform a write until the read has cleared | 395 | /* cannot perform a write until the read has cleared |
455 | either via tpm_read or a user_read_timer timeout */ | 396 | either via tpm_read or a user_read_timer timeout */ |
456 | while (atomic_read(&chip->data_pending) != 0) { | 397 | while (atomic_read(&chip->data_pending) != 0) |
457 | set_current_state(TASK_UNINTERRUPTIBLE); | 398 | msleep(TPM_TIMEOUT); |
458 | schedule_timeout(TPM_TIMEOUT); | ||
459 | } | ||
460 | 399 | ||
461 | down(&chip->buffer_mutex); | 400 | down(&chip->buffer_mutex); |
462 | 401 | ||
@@ -476,13 +415,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf, | |||
476 | up(&chip->buffer_mutex); | 415 | up(&chip->buffer_mutex); |
477 | 416 | ||
478 | /* Set a timeout by which the reader must come claim the result */ | 417 | /* Set a timeout by which the reader must come claim the result */ |
479 | down(&chip->timer_manipulation_mutex); | 418 | mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); |
480 | init_timer(&chip->user_read_timer); | ||
481 | chip->user_read_timer.function = user_reader_timeout; | ||
482 | chip->user_read_timer.data = (unsigned long) chip; | ||
483 | chip->user_read_timer.expires = jiffies + (60 * HZ); | ||
484 | add_timer(&chip->user_read_timer); | ||
485 | up(&chip->timer_manipulation_mutex); | ||
486 | 419 | ||
487 | return in_size; | 420 | return in_size; |
488 | } | 421 | } |
@@ -493,29 +426,19 @@ ssize_t tpm_read(struct file * file, char __user * buf, | |||
493 | size_t size, loff_t * off) | 426 | size_t size, loff_t * off) |
494 | { | 427 | { |
495 | struct tpm_chip *chip = file->private_data; | 428 | struct tpm_chip *chip = file->private_data; |
496 | int ret_size = -ENODATA; | 429 | int ret_size; |
497 | 430 | ||
498 | if (atomic_read(&chip->data_pending) != 0) { /* Result available */ | 431 | del_singleshot_timer_sync(&chip->user_read_timer); |
499 | down(&chip->timer_manipulation_mutex); | 432 | ret_size = atomic_read(&chip->data_pending); |
500 | del_singleshot_timer_sync(&chip->user_read_timer); | 433 | atomic_set(&chip->data_pending, 0); |
501 | up(&chip->timer_manipulation_mutex); | 434 | if (ret_size > 0) { /* relay data */ |
435 | if (size < ret_size) | ||
436 | ret_size = size; | ||
502 | 437 | ||
503 | down(&chip->buffer_mutex); | 438 | down(&chip->buffer_mutex); |
504 | 439 | if (copy_to_user | |
505 | ret_size = atomic_read(&chip->data_pending); | 440 | ((void __user *) buf, chip->data_buffer, ret_size)) |
506 | atomic_set(&chip->data_pending, 0); | 441 | ret_size = -EFAULT; |
507 | |||
508 | if (ret_size == 0) /* timeout just occurred */ | ||
509 | ret_size = -ETIME; | ||
510 | else if (ret_size > 0) { /* relay data */ | ||
511 | if (size < ret_size) | ||
512 | ret_size = size; | ||
513 | |||
514 | if (copy_to_user((void __user *) buf, | ||
515 | chip->data_buffer, ret_size)) { | ||
516 | ret_size = -EFAULT; | ||
517 | } | ||
518 | } | ||
519 | up(&chip->buffer_mutex); | 442 | up(&chip->buffer_mutex); |
520 | } | 443 | } |
521 | 444 | ||
@@ -541,14 +464,13 @@ void __devexit tpm_remove(struct pci_dev *pci_dev) | |||
541 | 464 | ||
542 | pci_set_drvdata(pci_dev, NULL); | 465 | pci_set_drvdata(pci_dev, NULL); |
543 | misc_deregister(&chip->vendor->miscdev); | 466 | misc_deregister(&chip->vendor->miscdev); |
467 | kfree(&chip->vendor->miscdev.name); | ||
544 | 468 | ||
545 | device_remove_file(&pci_dev->dev, &dev_attr_pubek); | 469 | sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group); |
546 | device_remove_file(&pci_dev->dev, &dev_attr_pcrs); | ||
547 | device_remove_file(&pci_dev->dev, &dev_attr_caps); | ||
548 | 470 | ||
549 | pci_disable_device(pci_dev); | 471 | pci_disable_device(pci_dev); |
550 | 472 | ||
551 | dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32)); | 473 | dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); |
552 | 474 | ||
553 | kfree(chip); | 475 | kfree(chip); |
554 | 476 | ||
@@ -590,10 +512,6 @@ int tpm_pm_resume(struct pci_dev *pci_dev) | |||
590 | if (chip == NULL) | 512 | if (chip == NULL) |
591 | return -ENODEV; | 513 | return -ENODEV; |
592 | 514 | ||
593 | spin_lock(&driver_lock); | ||
594 | tpm_lpc_bus_init(pci_dev, chip->vendor->base); | ||
595 | spin_unlock(&driver_lock); | ||
596 | |||
597 | return 0; | 515 | return 0; |
598 | } | 516 | } |
599 | 517 | ||
@@ -609,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); | |||
609 | int tpm_register_hardware(struct pci_dev *pci_dev, | 527 | int tpm_register_hardware(struct pci_dev *pci_dev, |
610 | struct tpm_vendor_specific *entry) | 528 | struct tpm_vendor_specific *entry) |
611 | { | 529 | { |
612 | char devname[7]; | 530 | #define DEVNAME_SIZE 7 |
531 | |||
532 | char *devname; | ||
613 | struct tpm_chip *chip; | 533 | struct tpm_chip *chip; |
614 | int i, j; | 534 | int i, j; |
615 | 535 | ||
@@ -622,17 +542,21 @@ int tpm_register_hardware(struct pci_dev *pci_dev, | |||
622 | 542 | ||
623 | init_MUTEX(&chip->buffer_mutex); | 543 | init_MUTEX(&chip->buffer_mutex); |
624 | init_MUTEX(&chip->tpm_mutex); | 544 | init_MUTEX(&chip->tpm_mutex); |
625 | init_MUTEX(&chip->timer_manipulation_mutex); | ||
626 | INIT_LIST_HEAD(&chip->list); | 545 | INIT_LIST_HEAD(&chip->list); |
627 | 546 | ||
547 | init_timer(&chip->user_read_timer); | ||
548 | chip->user_read_timer.function = user_reader_timeout; | ||
549 | chip->user_read_timer.data = (unsigned long) chip; | ||
550 | |||
628 | chip->vendor = entry; | 551 | chip->vendor = entry; |
629 | 552 | ||
630 | chip->dev_num = -1; | 553 | chip->dev_num = -1; |
631 | 554 | ||
632 | for (i = 0; i < 32; i++) | 555 | for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) |
633 | for (j = 0; j < 8; j++) | 556 | for (j = 0; j < 8 * sizeof(int); j++) |
634 | if ((dev_mask[i] & (1 << j)) == 0) { | 557 | if ((dev_mask[i] & (1 << j)) == 0) { |
635 | chip->dev_num = i * 32 + j; | 558 | chip->dev_num = |
559 | i * TPM_NUM_MASK_ENTRIES + j; | ||
636 | dev_mask[i] |= 1 << j; | 560 | dev_mask[i] |= 1 << j; |
637 | goto dev_num_search_complete; | 561 | goto dev_num_search_complete; |
638 | } | 562 | } |
@@ -648,7 +572,8 @@ dev_num_search_complete: | |||
648 | else | 572 | else |
649 | chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; | 573 | chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; |
650 | 574 | ||
651 | snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num); | 575 | devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); |
576 | scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); | ||
652 | chip->vendor->miscdev.name = devname; | 577 | chip->vendor->miscdev.name = devname; |
653 | 578 | ||
654 | chip->vendor->miscdev.dev = &(pci_dev->dev); | 579 | chip->vendor->miscdev.dev = &(pci_dev->dev); |
@@ -665,31 +590,20 @@ dev_num_search_complete: | |||
665 | return -ENODEV; | 590 | return -ENODEV; |
666 | } | 591 | } |
667 | 592 | ||
593 | spin_lock(&driver_lock); | ||
594 | |||
668 | pci_set_drvdata(pci_dev, chip); | 595 | pci_set_drvdata(pci_dev, chip); |
669 | 596 | ||
670 | list_add(&chip->list, &tpm_chip_list); | 597 | list_add(&chip->list, &tpm_chip_list); |
671 | 598 | ||
672 | device_create_file(&pci_dev->dev, &dev_attr_pubek); | 599 | spin_unlock(&driver_lock); |
673 | device_create_file(&pci_dev->dev, &dev_attr_pcrs); | ||
674 | device_create_file(&pci_dev->dev, &dev_attr_caps); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | 600 | ||
679 | EXPORT_SYMBOL_GPL(tpm_register_hardware); | 601 | sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group); |
680 | 602 | ||
681 | static int __init init_tpm(void) | ||
682 | { | ||
683 | return 0; | 603 | return 0; |
684 | } | 604 | } |
685 | 605 | ||
686 | static void __exit cleanup_tpm(void) | 606 | EXPORT_SYMBOL_GPL(tpm_register_hardware); |
687 | { | ||
688 | |||
689 | } | ||
690 | |||
691 | module_init(init_tpm); | ||
692 | module_exit(cleanup_tpm); | ||
693 | 607 | ||
694 | MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); | 608 | MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); |
695 | MODULE_DESCRIPTION("TPM Driver"); | 609 | MODULE_DESCRIPTION("TPM Driver"); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index de0c796fce80..373b41f6b460 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -25,23 +25,38 @@ | |||
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/miscdevice.h> | 26 | #include <linux/miscdevice.h> |
27 | 27 | ||
28 | #define TPM_TIMEOUT msecs_to_jiffies(5) | 28 | enum tpm_timeout { |
29 | TPM_TIMEOUT = 5, /* msecs */ | ||
30 | }; | ||
29 | 31 | ||
30 | /* TPM addresses */ | 32 | /* TPM addresses */ |
31 | #define TPM_ADDR 0x4E | 33 | enum tpm_addr { |
32 | #define TPM_DATA 0x4F | 34 | TPM_SUPERIO_ADDR = 0x2E, |
35 | TPM_ADDR = 0x4E, | ||
36 | }; | ||
37 | |||
38 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, | ||
39 | char *); | ||
40 | extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, | ||
41 | char *); | ||
42 | extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, | ||
43 | char *); | ||
44 | extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, | ||
45 | const char *, size_t); | ||
33 | 46 | ||
34 | struct tpm_chip; | 47 | struct tpm_chip; |
35 | 48 | ||
36 | struct tpm_vendor_specific { | 49 | struct tpm_vendor_specific { |
37 | u8 req_complete_mask; | 50 | u8 req_complete_mask; |
38 | u8 req_complete_val; | 51 | u8 req_complete_val; |
52 | u8 req_canceled; | ||
39 | u16 base; /* TPM base address */ | 53 | u16 base; /* TPM base address */ |
40 | 54 | ||
41 | int (*recv) (struct tpm_chip *, u8 *, size_t); | 55 | int (*recv) (struct tpm_chip *, u8 *, size_t); |
42 | int (*send) (struct tpm_chip *, u8 *, size_t); | 56 | int (*send) (struct tpm_chip *, u8 *, size_t); |
43 | void (*cancel) (struct tpm_chip *); | 57 | void (*cancel) (struct tpm_chip *); |
44 | struct miscdevice miscdev; | 58 | struct miscdevice miscdev; |
59 | struct attribute_group *attr_group; | ||
45 | }; | 60 | }; |
46 | 61 | ||
47 | struct tpm_chip { | 62 | struct tpm_chip { |
@@ -58,29 +73,24 @@ struct tpm_chip { | |||
58 | 73 | ||
59 | struct timer_list user_read_timer; /* user needs to claim result */ | 74 | struct timer_list user_read_timer; /* user needs to claim result */ |
60 | struct semaphore tpm_mutex; /* tpm is processing */ | 75 | struct semaphore tpm_mutex; /* tpm is processing */ |
61 | struct timer_list device_timer; /* tpm is processing */ | ||
62 | struct semaphore timer_manipulation_mutex; | ||
63 | 76 | ||
64 | struct tpm_vendor_specific *vendor; | 77 | struct tpm_vendor_specific *vendor; |
65 | 78 | ||
66 | struct list_head list; | 79 | struct list_head list; |
67 | }; | 80 | }; |
68 | 81 | ||
69 | static inline int tpm_read_index(int index) | 82 | static inline int tpm_read_index(int base, int index) |
70 | { | 83 | { |
71 | outb(index, TPM_ADDR); | 84 | outb(index, base); |
72 | return inb(TPM_DATA) & 0xFF; | 85 | return inb(base+1) & 0xFF; |
73 | } | 86 | } |
74 | 87 | ||
75 | static inline void tpm_write_index(int index, int value) | 88 | static inline void tpm_write_index(int base, int index, int value) |
76 | { | 89 | { |
77 | outb(index, TPM_ADDR); | 90 | outb(index, base); |
78 | outb(value & 0xFF, TPM_DATA); | 91 | outb(value & 0xFF, base+1); |
79 | } | 92 | } |
80 | 93 | ||
81 | extern void tpm_time_expired(unsigned long); | ||
82 | extern int tpm_lpc_bus_init(struct pci_dev *, u16); | ||
83 | |||
84 | extern int tpm_register_hardware(struct pci_dev *, | 94 | extern int tpm_register_hardware(struct pci_dev *, |
85 | struct tpm_vendor_specific *); | 95 | struct tpm_vendor_specific *); |
86 | extern int tpm_open(struct inode *, struct file *); | 96 | 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 f9333e729b62..cc2cc77fd174 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
@@ -22,17 +22,23 @@ | |||
22 | #include "tpm.h" | 22 | #include "tpm.h" |
23 | 23 | ||
24 | /* Atmel definitions */ | 24 | /* Atmel definitions */ |
25 | #define TPM_ATML_BASE 0x400 | 25 | enum tpm_atmel_addr { |
26 | TPM_ATMEL_BASE_ADDR_LO = 0x08, | ||
27 | TPM_ATMEL_BASE_ADDR_HI = 0x09 | ||
28 | }; | ||
26 | 29 | ||
27 | /* write status bits */ | 30 | /* write status bits */ |
28 | #define ATML_STATUS_ABORT 0x01 | 31 | enum tpm_atmel_write_status { |
29 | #define ATML_STATUS_LASTBYTE 0x04 | 32 | ATML_STATUS_ABORT = 0x01, |
30 | 33 | ATML_STATUS_LASTBYTE = 0x04 | |
34 | }; | ||
31 | /* read status bits */ | 35 | /* read status bits */ |
32 | #define ATML_STATUS_BUSY 0x01 | 36 | enum tpm_atmel_read_status { |
33 | #define ATML_STATUS_DATA_AVAIL 0x02 | 37 | ATML_STATUS_BUSY = 0x01, |
34 | #define ATML_STATUS_REWRITE 0x04 | 38 | ATML_STATUS_DATA_AVAIL = 0x02, |
35 | 39 | ATML_STATUS_REWRITE = 0x04, | |
40 | ATML_STATUS_READY = 0x08 | ||
41 | }; | ||
36 | 42 | ||
37 | static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | 43 | static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) |
38 | { | 44 | { |
@@ -121,13 +127,29 @@ static struct file_operations atmel_ops = { | |||
121 | .release = tpm_release, | 127 | .release = tpm_release, |
122 | }; | 128 | }; |
123 | 129 | ||
130 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
131 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
132 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
133 | static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); | ||
134 | |||
135 | static struct attribute* atmel_attrs[] = { | ||
136 | &dev_attr_pubek.attr, | ||
137 | &dev_attr_pcrs.attr, | ||
138 | &dev_attr_caps.attr, | ||
139 | &dev_attr_cancel.attr, | ||
140 | 0, | ||
141 | }; | ||
142 | |||
143 | static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; | ||
144 | |||
124 | static struct tpm_vendor_specific tpm_atmel = { | 145 | static struct tpm_vendor_specific tpm_atmel = { |
125 | .recv = tpm_atml_recv, | 146 | .recv = tpm_atml_recv, |
126 | .send = tpm_atml_send, | 147 | .send = tpm_atml_send, |
127 | .cancel = tpm_atml_cancel, | 148 | .cancel = tpm_atml_cancel, |
128 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, | 149 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, |
129 | .req_complete_val = ATML_STATUS_DATA_AVAIL, | 150 | .req_complete_val = ATML_STATUS_DATA_AVAIL, |
130 | .base = TPM_ATML_BASE, | 151 | .req_canceled = ATML_STATUS_READY, |
152 | .attr_group = &atmel_attr_grp, | ||
131 | .miscdev = { .fops = &atmel_ops, }, | 153 | .miscdev = { .fops = &atmel_ops, }, |
132 | }; | 154 | }; |
133 | 155 | ||
@@ -136,27 +158,29 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev, | |||
136 | { | 158 | { |
137 | u8 version[4]; | 159 | u8 version[4]; |
138 | int rc = 0; | 160 | int rc = 0; |
161 | int lo, hi; | ||
139 | 162 | ||
140 | if (pci_enable_device(pci_dev)) | 163 | if (pci_enable_device(pci_dev)) |
141 | return -EIO; | 164 | return -EIO; |
142 | 165 | ||
143 | if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) { | 166 | lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); |
144 | rc = -ENODEV; | 167 | hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); |
145 | goto out_err; | 168 | |
146 | } | 169 | tpm_atmel.base = (hi<<8)|lo; |
170 | dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); | ||
147 | 171 | ||
148 | /* verify that it is an Atmel part */ | 172 | /* verify that it is an Atmel part */ |
149 | if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T' | 173 | if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' |
150 | || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') { | 174 | || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { |
151 | rc = -ENODEV; | 175 | rc = -ENODEV; |
152 | goto out_err; | 176 | goto out_err; |
153 | } | 177 | } |
154 | 178 | ||
155 | /* query chip for its version number */ | 179 | /* query chip for its version number */ |
156 | if ((version[0] = tpm_read_index(0x00)) != 0xFF) { | 180 | if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { |
157 | version[1] = tpm_read_index(0x01); | 181 | version[1] = tpm_read_index(TPM_ADDR, 0x01); |
158 | version[2] = tpm_read_index(0x02); | 182 | version[2] = tpm_read_index(TPM_ADDR, 0x02); |
159 | version[3] = tpm_read_index(0x03); | 183 | version[3] = tpm_read_index(TPM_ADDR, 0x03); |
160 | } else { | 184 | } else { |
161 | dev_info(&pci_dev->dev, "version query failed\n"); | 185 | dev_info(&pci_dev->dev, "version query failed\n"); |
162 | rc = -ENODEV; | 186 | rc = -ENODEV; |
@@ -183,6 +207,7 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { | |||
183 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, | 207 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, |
184 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, | 208 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, |
185 | {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, | 209 | {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, |
210 | {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, | ||
186 | {0,} | 211 | {0,} |
187 | }; | 212 | }; |
188 | 213 | ||
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 9cce833a0923..b4127348c063 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c | |||
@@ -22,43 +22,52 @@ | |||
22 | #include "tpm.h" | 22 | #include "tpm.h" |
23 | 23 | ||
24 | /* National definitions */ | 24 | /* National definitions */ |
25 | #define TPM_NSC_BASE 0x360 | 25 | enum tpm_nsc_addr{ |
26 | #define TPM_NSC_IRQ 0x07 | 26 | TPM_NSC_IRQ = 0x07, |
27 | TPM_NSC_BASE0_HI = 0x60, | ||
28 | TPM_NSC_BASE0_LO = 0x61, | ||
29 | TPM_NSC_BASE1_HI = 0x62, | ||
30 | TPM_NSC_BASE1_LO = 0x63 | ||
31 | }; | ||
27 | 32 | ||
28 | #define NSC_LDN_INDEX 0x07 | 33 | enum tpm_nsc_index { |
29 | #define NSC_SID_INDEX 0x20 | 34 | NSC_LDN_INDEX = 0x07, |
30 | #define NSC_LDC_INDEX 0x30 | 35 | NSC_SID_INDEX = 0x20, |
31 | #define NSC_DIO_INDEX 0x60 | 36 | NSC_LDC_INDEX = 0x30, |
32 | #define NSC_CIO_INDEX 0x62 | 37 | NSC_DIO_INDEX = 0x60, |
33 | #define NSC_IRQ_INDEX 0x70 | 38 | NSC_CIO_INDEX = 0x62, |
34 | #define NSC_ITS_INDEX 0x71 | 39 | NSC_IRQ_INDEX = 0x70, |
40 | NSC_ITS_INDEX = 0x71 | ||
41 | }; | ||
35 | 42 | ||
36 | #define NSC_STATUS 0x01 | 43 | enum tpm_nsc_status_loc { |
37 | #define NSC_COMMAND 0x01 | 44 | NSC_STATUS = 0x01, |
38 | #define NSC_DATA 0x00 | 45 | NSC_COMMAND = 0x01, |
46 | NSC_DATA = 0x00 | ||
47 | }; | ||
39 | 48 | ||
40 | /* status bits */ | 49 | /* status bits */ |
41 | #define NSC_STATUS_OBF 0x01 /* output buffer full */ | 50 | enum tpm_nsc_status { |
42 | #define NSC_STATUS_IBF 0x02 /* input buffer full */ | 51 | NSC_STATUS_OBF = 0x01, /* output buffer full */ |
43 | #define NSC_STATUS_F0 0x04 /* F0 */ | 52 | NSC_STATUS_IBF = 0x02, /* input buffer full */ |
44 | #define NSC_STATUS_A2 0x08 /* A2 */ | 53 | NSC_STATUS_F0 = 0x04, /* F0 */ |
45 | #define NSC_STATUS_RDY 0x10 /* ready to receive command */ | 54 | NSC_STATUS_A2 = 0x08, /* A2 */ |
46 | #define NSC_STATUS_IBR 0x20 /* ready to receive data */ | 55 | NSC_STATUS_RDY = 0x10, /* ready to receive command */ |
56 | NSC_STATUS_IBR = 0x20 /* ready to receive data */ | ||
57 | }; | ||
47 | 58 | ||
48 | /* command bits */ | 59 | /* command bits */ |
49 | #define NSC_COMMAND_NORMAL 0x01 /* normal mode */ | 60 | enum tpm_nsc_cmd_mode { |
50 | #define NSC_COMMAND_EOC 0x03 | 61 | NSC_COMMAND_NORMAL = 0x01, /* normal mode */ |
51 | #define NSC_COMMAND_CANCEL 0x22 | 62 | NSC_COMMAND_EOC = 0x03, |
52 | 63 | NSC_COMMAND_CANCEL = 0x22 | |
64 | }; | ||
53 | /* | 65 | /* |
54 | * Wait for a certain status to appear | 66 | * Wait for a certain status to appear |
55 | */ | 67 | */ |
56 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) | 68 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) |
57 | { | 69 | { |
58 | int expired = 0; | 70 | unsigned long stop; |
59 | struct timer_list status_timer = | ||
60 | TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ, | ||
61 | (unsigned long) &expired); | ||
62 | 71 | ||
63 | /* status immediately available check */ | 72 | /* status immediately available check */ |
64 | *data = inb(chip->vendor->base + NSC_STATUS); | 73 | *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) | |||
66 | return 0; | 75 | return 0; |
67 | 76 | ||
68 | /* wait for status */ | 77 | /* wait for status */ |
69 | add_timer(&status_timer); | 78 | stop = jiffies + 10 * HZ; |
70 | do { | 79 | do { |
71 | set_current_state(TASK_UNINTERRUPTIBLE); | 80 | msleep(TPM_TIMEOUT); |
72 | schedule_timeout(TPM_TIMEOUT); | ||
73 | *data = inb(chip->vendor->base + 1); | 81 | *data = inb(chip->vendor->base + 1); |
74 | if ((*data & mask) == val) { | 82 | if ((*data & mask) == val) |
75 | del_singleshot_timer_sync(&status_timer); | ||
76 | return 0; | 83 | return 0; |
77 | } | ||
78 | } | 84 | } |
79 | while (!expired); | 85 | while (time_before(jiffies, stop)); |
80 | 86 | ||
81 | return -EBUSY; | 87 | return -EBUSY; |
82 | } | 88 | } |
@@ -84,10 +90,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) | |||
84 | static int nsc_wait_for_ready(struct tpm_chip *chip) | 90 | static int nsc_wait_for_ready(struct tpm_chip *chip) |
85 | { | 91 | { |
86 | int status; | 92 | int status; |
87 | int expired = 0; | 93 | unsigned long stop; |
88 | struct timer_list status_timer = | ||
89 | TIMER_INITIALIZER(tpm_time_expired, jiffies + 100, | ||
90 | (unsigned long) &expired); | ||
91 | 94 | ||
92 | /* status immediately available check */ | 95 | /* status immediately available check */ |
93 | status = inb(chip->vendor->base + NSC_STATUS); | 96 | status = inb(chip->vendor->base + NSC_STATUS); |
@@ -97,19 +100,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) | |||
97 | return 0; | 100 | return 0; |
98 | 101 | ||
99 | /* wait for status */ | 102 | /* wait for status */ |
100 | add_timer(&status_timer); | 103 | stop = jiffies + 100; |
101 | do { | 104 | do { |
102 | set_current_state(TASK_UNINTERRUPTIBLE); | 105 | msleep(TPM_TIMEOUT); |
103 | schedule_timeout(TPM_TIMEOUT); | ||
104 | status = inb(chip->vendor->base + NSC_STATUS); | 106 | status = inb(chip->vendor->base + NSC_STATUS); |
105 | if (status & NSC_STATUS_OBF) | 107 | if (status & NSC_STATUS_OBF) |
106 | status = inb(chip->vendor->base + NSC_DATA); | 108 | status = inb(chip->vendor->base + NSC_DATA); |
107 | if (status & NSC_STATUS_RDY) { | 109 | if (status & NSC_STATUS_RDY) |
108 | del_singleshot_timer_sync(&status_timer); | ||
109 | return 0; | 110 | return 0; |
110 | } | ||
111 | } | 111 | } |
112 | while (!expired); | 112 | while (time_before(jiffies, stop)); |
113 | 113 | ||
114 | dev_info(&chip->pci_dev->dev, "wait for ready failed\n"); | 114 | dev_info(&chip->pci_dev->dev, "wait for ready failed\n"); |
115 | return -EBUSY; | 115 | return -EBUSY; |
@@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) | |||
150 | *p = inb(chip->vendor->base + NSC_DATA); | 150 | *p = inb(chip->vendor->base + NSC_DATA); |
151 | } | 151 | } |
152 | 152 | ||
153 | if ((data & NSC_STATUS_F0) == 0) { | 153 | if ((data & NSC_STATUS_F0) == 0 && |
154 | (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { | ||
154 | dev_err(&chip->pci_dev->dev, "F0 not set\n"); | 155 | dev_err(&chip->pci_dev->dev, "F0 not set\n"); |
155 | return -EIO; | 156 | return -EIO; |
156 | } | 157 | } |
@@ -228,100 +229,95 @@ static struct file_operations nsc_ops = { | |||
228 | .release = tpm_release, | 229 | .release = tpm_release, |
229 | }; | 230 | }; |
230 | 231 | ||
232 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
233 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
234 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
235 | static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel); | ||
236 | |||
237 | static struct attribute * nsc_attrs[] = { | ||
238 | &dev_attr_pubek.attr, | ||
239 | &dev_attr_pcrs.attr, | ||
240 | &dev_attr_caps.attr, | ||
241 | &dev_attr_cancel.attr, | ||
242 | 0, | ||
243 | }; | ||
244 | |||
245 | static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; | ||
246 | |||
231 | static struct tpm_vendor_specific tpm_nsc = { | 247 | static struct tpm_vendor_specific tpm_nsc = { |
232 | .recv = tpm_nsc_recv, | 248 | .recv = tpm_nsc_recv, |
233 | .send = tpm_nsc_send, | 249 | .send = tpm_nsc_send, |
234 | .cancel = tpm_nsc_cancel, | 250 | .cancel = tpm_nsc_cancel, |
235 | .req_complete_mask = NSC_STATUS_OBF, | 251 | .req_complete_mask = NSC_STATUS_OBF, |
236 | .req_complete_val = NSC_STATUS_OBF, | 252 | .req_complete_val = NSC_STATUS_OBF, |
237 | .base = TPM_NSC_BASE, | 253 | .req_canceled = NSC_STATUS_RDY, |
254 | .attr_group = &nsc_attr_grp, | ||
238 | .miscdev = { .fops = &nsc_ops, }, | 255 | .miscdev = { .fops = &nsc_ops, }, |
239 | |||
240 | }; | 256 | }; |
241 | 257 | ||
242 | static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, | 258 | static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, |
243 | const struct pci_device_id *pci_id) | 259 | const struct pci_device_id *pci_id) |
244 | { | 260 | { |
245 | int rc = 0; | 261 | int rc = 0; |
262 | int lo, hi; | ||
263 | int nscAddrBase = TPM_ADDR; | ||
264 | |||
246 | 265 | ||
247 | if (pci_enable_device(pci_dev)) | 266 | if (pci_enable_device(pci_dev)) |
248 | return -EIO; | 267 | return -EIO; |
249 | 268 | ||
250 | if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) { | 269 | /* select PM channel 1 */ |
251 | rc = -ENODEV; | 270 | tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); |
252 | goto out_err; | ||
253 | } | ||
254 | 271 | ||
255 | /* verify that it is a National part (SID) */ | 272 | /* verify that it is a National part (SID) */ |
256 | if (tpm_read_index(NSC_SID_INDEX) != 0xEF) { | 273 | if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { |
257 | rc = -ENODEV; | 274 | nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)| |
258 | goto out_err; | 275 | (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE); |
276 | if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) { | ||
277 | rc = -ENODEV; | ||
278 | goto out_err; | ||
279 | } | ||
259 | } | 280 | } |
260 | 281 | ||
282 | hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); | ||
283 | lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); | ||
284 | tpm_nsc.base = (hi<<8) | lo; | ||
285 | |||
261 | dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); | 286 | dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); |
262 | dev_dbg(&pci_dev->dev, | 287 | dev_dbg(&pci_dev->dev, |
263 | "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", | 288 | "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", |
264 | tpm_read_index(0x07), tpm_read_index(0x20), | 289 | tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20), |
265 | tpm_read_index(0x27)); | 290 | tpm_read_index(nscAddrBase,0x27)); |
266 | dev_dbg(&pci_dev->dev, | 291 | dev_dbg(&pci_dev->dev, |
267 | "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", | 292 | "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", |
268 | tpm_read_index(0x21), tpm_read_index(0x25), | 293 | tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25), |
269 | tpm_read_index(0x26), tpm_read_index(0x28)); | 294 | tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28)); |
270 | dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", | 295 | dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", |
271 | (tpm_read_index(0x60) << 8) | tpm_read_index(0x61)); | 296 | (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61)); |
272 | dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", | 297 | dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", |
273 | (tpm_read_index(0x62) << 8) | tpm_read_index(0x63)); | 298 | (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63)); |
274 | dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", | 299 | dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", |
275 | tpm_read_index(0x70)); | 300 | tpm_read_index(nscAddrBase,0x70)); |
276 | dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", | 301 | dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", |
277 | tpm_read_index(0x71)); | 302 | tpm_read_index(nscAddrBase,0x71)); |
278 | dev_dbg(&pci_dev->dev, | 303 | dev_dbg(&pci_dev->dev, |
279 | "NSC DMA channel select0 0x%x, select1 0x%x\n", | 304 | "NSC DMA channel select0 0x%x, select1 0x%x\n", |
280 | tpm_read_index(0x74), tpm_read_index(0x75)); | 305 | tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75)); |
281 | dev_dbg(&pci_dev->dev, | 306 | dev_dbg(&pci_dev->dev, |
282 | "NSC Config " | 307 | "NSC Config " |
283 | "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", | 308 | "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
284 | tpm_read_index(0xF0), tpm_read_index(0xF1), | 309 | tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1), |
285 | tpm_read_index(0xF2), tpm_read_index(0xF3), | 310 | tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3), |
286 | tpm_read_index(0xF4), tpm_read_index(0xF5), | 311 | tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5), |
287 | tpm_read_index(0xF6), tpm_read_index(0xF7), | 312 | tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7), |
288 | tpm_read_index(0xF8), tpm_read_index(0xF9)); | 313 | tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9)); |
289 | 314 | ||
290 | dev_info(&pci_dev->dev, | 315 | dev_info(&pci_dev->dev, |
291 | "NSC PC21100 TPM revision %d\n", | 316 | "NSC TPM revision %d\n", |
292 | tpm_read_index(0x27) & 0x1F); | 317 | tpm_read_index(nscAddrBase, 0x27) & 0x1F); |
293 | |||
294 | if (tpm_read_index(NSC_LDC_INDEX) == 0) | ||
295 | dev_info(&pci_dev->dev, ": NSC TPM not active\n"); | ||
296 | |||
297 | /* select PM channel 1 */ | ||
298 | tpm_write_index(NSC_LDN_INDEX, 0x12); | ||
299 | tpm_read_index(NSC_LDN_INDEX); | ||
300 | |||
301 | /* disable the DPM module */ | ||
302 | tpm_write_index(NSC_LDC_INDEX, 0); | ||
303 | tpm_read_index(NSC_LDC_INDEX); | ||
304 | |||
305 | /* set the data register base addresses */ | ||
306 | tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8); | ||
307 | tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE); | ||
308 | tpm_read_index(NSC_DIO_INDEX); | ||
309 | tpm_read_index(NSC_DIO_INDEX + 1); | ||
310 | |||
311 | /* set the command register base addresses */ | ||
312 | tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8); | ||
313 | tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1)); | ||
314 | tpm_read_index(NSC_DIO_INDEX); | ||
315 | tpm_read_index(NSC_DIO_INDEX + 1); | ||
316 | |||
317 | /* set the interrupt number to be used for the host interface */ | ||
318 | tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ); | ||
319 | tpm_write_index(NSC_ITS_INDEX, 0x00); | ||
320 | tpm_read_index(NSC_IRQ_INDEX); | ||
321 | 318 | ||
322 | /* enable the DPM module */ | 319 | /* enable the DPM module */ |
323 | tpm_write_index(NSC_LDC_INDEX, 0x01); | 320 | tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); |
324 | tpm_read_index(NSC_LDC_INDEX); | ||
325 | 321 | ||
326 | if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0) | 322 | if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0) |
327 | goto out_err; | 323 | goto out_err; |
@@ -339,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { | |||
339 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, | 335 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, |
340 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, | 336 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, |
341 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, | 337 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, |
338 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, | ||
339 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, | ||
340 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, | ||
342 | {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, | 341 | {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, |
343 | {0,} | 342 | {0,} |
344 | }; | 343 | }; |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 31831030f73f..6e4be3bb2d89 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -94,6 +94,7 @@ | |||
94 | #include <linux/idr.h> | 94 | #include <linux/idr.h> |
95 | #include <linux/wait.h> | 95 | #include <linux/wait.h> |
96 | #include <linux/bitops.h> | 96 | #include <linux/bitops.h> |
97 | #include <linux/delay.h> | ||
97 | 98 | ||
98 | #include <asm/uaccess.h> | 99 | #include <asm/uaccess.h> |
99 | #include <asm/system.h> | 100 | #include <asm/system.h> |
@@ -251,7 +252,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |||
251 | 252 | ||
252 | static DEFINE_SPINLOCK(tty_ldisc_lock); | 253 | static DEFINE_SPINLOCK(tty_ldisc_lock); |
253 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); | 254 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); |
254 | static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ | 255 | static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ |
255 | 256 | ||
256 | int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) | 257 | int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) |
257 | { | 258 | { |
@@ -262,24 +263,35 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) | |||
262 | return -EINVAL; | 263 | return -EINVAL; |
263 | 264 | ||
264 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 265 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
265 | if (new_ldisc) { | 266 | tty_ldiscs[disc] = *new_ldisc; |
266 | tty_ldiscs[disc] = *new_ldisc; | 267 | tty_ldiscs[disc].num = disc; |
267 | tty_ldiscs[disc].num = disc; | 268 | tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; |
268 | tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; | 269 | tty_ldiscs[disc].refcount = 0; |
269 | tty_ldiscs[disc].refcount = 0; | ||
270 | } else { | ||
271 | if(tty_ldiscs[disc].refcount) | ||
272 | ret = -EBUSY; | ||
273 | else | ||
274 | tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; | ||
275 | } | ||
276 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 270 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
277 | 271 | ||
278 | return ret; | 272 | return ret; |
279 | } | 273 | } |
280 | |||
281 | EXPORT_SYMBOL(tty_register_ldisc); | 274 | EXPORT_SYMBOL(tty_register_ldisc); |
282 | 275 | ||
276 | int tty_unregister_ldisc(int disc) | ||
277 | { | ||
278 | unsigned long flags; | ||
279 | int ret = 0; | ||
280 | |||
281 | if (disc < N_TTY || disc >= NR_LDISCS) | ||
282 | return -EINVAL; | ||
283 | |||
284 | spin_lock_irqsave(&tty_ldisc_lock, flags); | ||
285 | if (tty_ldiscs[disc].refcount) | ||
286 | ret = -EBUSY; | ||
287 | else | ||
288 | tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; | ||
289 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
290 | |||
291 | return ret; | ||
292 | } | ||
293 | EXPORT_SYMBOL(tty_unregister_ldisc); | ||
294 | |||
283 | struct tty_ldisc *tty_ldisc_get(int disc) | 295 | struct tty_ldisc *tty_ldisc_get(int disc) |
284 | { | 296 | { |
285 | unsigned long flags; | 297 | unsigned long flags; |
@@ -2169,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) | |||
2169 | return tty_set_ldisc(tty, ldisc); | 2181 | return tty_set_ldisc(tty, ldisc); |
2170 | } | 2182 | } |
2171 | 2183 | ||
2172 | static int send_break(struct tty_struct *tty, int duration) | 2184 | static int send_break(struct tty_struct *tty, unsigned int duration) |
2173 | { | 2185 | { |
2174 | tty->driver->break_ctl(tty, -1); | 2186 | tty->driver->break_ctl(tty, -1); |
2175 | if (!signal_pending(current)) { | 2187 | if (!signal_pending(current)) { |
2176 | set_current_state(TASK_INTERRUPTIBLE); | 2188 | msleep_interruptible(duration); |
2177 | schedule_timeout(duration); | ||
2178 | } | 2189 | } |
2179 | tty->driver->break_ctl(tty, 0); | 2190 | tty->driver->break_ctl(tty, 0); |
2180 | if (signal_pending(current)) | 2191 | if (signal_pending(current)) |
@@ -2355,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
2355 | * all by anyone? | 2366 | * all by anyone? |
2356 | */ | 2367 | */ |
2357 | if (!arg) | 2368 | if (!arg) |
2358 | return send_break(tty, HZ/4); | 2369 | return send_break(tty, 250); |
2359 | return 0; | 2370 | return 0; |
2360 | case TCSBRKP: /* support for POSIX tcsendbreak() */ | 2371 | case TCSBRKP: /* support for POSIX tcsendbreak() */ |
2361 | return send_break(tty, arg ? arg*(HZ/10) : HZ/4); | 2372 | return send_break(tty, arg ? arg*100 : 250); |
2362 | 2373 | ||
2363 | case TIOCMGET: | 2374 | case TIOCMGET: |
2364 | return tty_tiocmget(tty, file, p); | 2375 | return tty_tiocmget(tty, file, p); |
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 06a31da2381c..b53e2e2b5aee 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -414,6 +414,16 @@ config WATCHDOG_RIO | |||
414 | machines. The watchdog timeout period is normally one minute but | 414 | machines. The watchdog timeout period is normally one minute but |
415 | can be changed with a boot-time parameter. | 415 | can be changed with a boot-time parameter. |
416 | 416 | ||
417 | # ppc64 RTAS watchdog | ||
418 | config WATCHDOG_RTAS | ||
419 | tristate "RTAS watchdog" | ||
420 | depends on WATCHDOG && PPC_RTAS | ||
421 | help | ||
422 | This driver adds watchdog support for the RTAS watchdog. | ||
423 | |||
424 | To compile this driver as a module, choose M here. The module | ||
425 | will be called wdrtas. | ||
426 | |||
417 | # | 427 | # |
418 | # ISA-based Watchdog Cards | 428 | # ISA-based Watchdog Cards |
419 | # | 429 | # |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 1cd27efa35c1..c1838834ea7f 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -33,6 +33,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o | |||
33 | obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o | 33 | obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o |
34 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o | 34 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o |
35 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o | 35 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o |
36 | obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o | ||
36 | 37 | ||
37 | # Only one watchdog can succeed. We probe the hardware watchdog | 38 | # Only one watchdog can succeed. We probe the hardware watchdog |
38 | # drivers first, then the softdog driver. This means if your hardware | 39 | # 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 000000000000..619e2ffca33f --- /dev/null +++ b/drivers/char/watchdog/wdrtas.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as | ||
3 | * RTAS calls are available | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * RTAS watchdog driver | ||
8 | * | ||
9 | * (C) Copyright IBM Corp. 2005 | ||
10 | * device driver to exploit watchdog RTAS functions | ||
11 | * | ||
12 | * Authors : Utz Bacher <utz.bacher@de.ibm.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2, or (at your option) | ||
17 | * any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #include <linux/config.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/miscdevice.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/notifier.h> | ||
36 | #include <linux/reboot.h> | ||
37 | #include <linux/types.h> | ||
38 | #include <linux/watchdog.h> | ||
39 | |||
40 | #include <asm/rtas.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | |||
43 | #define WDRTAS_MAGIC_CHAR 42 | ||
44 | #define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ | ||
45 | WDIOF_MAGICCLOSE) | ||
46 | |||
47 | MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); | ||
48 | MODULE_DESCRIPTION("RTAS watchdog driver"); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
51 | MODULE_ALIAS_MISCDEV(TEMP_MINOR); | ||
52 | |||
53 | #ifdef CONFIG_WATCHDOG_NOWAYOUT | ||
54 | static int wdrtas_nowayout = 1; | ||
55 | #else | ||
56 | static int wdrtas_nowayout = 0; | ||
57 | #endif | ||
58 | |||
59 | static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); | ||
60 | static char wdrtas_expect_close = 0; | ||
61 | |||
62 | static int wdrtas_interval; | ||
63 | |||
64 | #define WDRTAS_THERMAL_SENSOR 3 | ||
65 | static int wdrtas_token_get_sensor_state; | ||
66 | #define WDRTAS_SURVEILLANCE_IND 9000 | ||
67 | static int wdrtas_token_set_indicator; | ||
68 | #define WDRTAS_SP_SPI 28 | ||
69 | static int wdrtas_token_get_sp; | ||
70 | static int wdrtas_token_event_scan; | ||
71 | |||
72 | #define WDRTAS_DEFAULT_INTERVAL 300 | ||
73 | |||
74 | #define WDRTAS_LOGBUFFER_LEN 128 | ||
75 | static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; | ||
76 | |||
77 | |||
78 | /*** watchdog access functions */ | ||
79 | |||
80 | /** | ||
81 | * wdrtas_set_interval - sets the watchdog interval | ||
82 | * @interval: new interval | ||
83 | * | ||
84 | * returns 0 on success, <0 on failures | ||
85 | * | ||
86 | * wdrtas_set_interval sets the watchdog keepalive interval by calling the | ||
87 | * RTAS function set-indicator (surveillance). The unit of interval is | ||
88 | * seconds. | ||
89 | */ | ||
90 | static int | ||
91 | wdrtas_set_interval(int interval) | ||
92 | { | ||
93 | long result; | ||
94 | static int print_msg = 10; | ||
95 | |||
96 | /* rtas uses minutes */ | ||
97 | interval = (interval + 59) / 60; | ||
98 | |||
99 | result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, | ||
100 | WDRTAS_SURVEILLANCE_IND, 0, interval); | ||
101 | if ( (result < 0) && (print_msg) ) { | ||
102 | printk(KERN_ERR "wdrtas: setting the watchdog to %i " | ||
103 | "timeout failed: %li\n", interval, result); | ||
104 | print_msg--; | ||
105 | } | ||
106 | |||
107 | return result; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * wdrtas_get_interval - returns the current watchdog interval | ||
112 | * @fallback_value: value (in seconds) to use, if the RTAS call fails | ||
113 | * | ||
114 | * returns the interval | ||
115 | * | ||
116 | * wdrtas_get_interval returns the current watchdog keepalive interval | ||
117 | * as reported by the RTAS function ibm,get-system-parameter. The unit | ||
118 | * of the return value is seconds. | ||
119 | */ | ||
120 | static int | ||
121 | wdrtas_get_interval(int fallback_value) | ||
122 | { | ||
123 | long result; | ||
124 | char value[4]; | ||
125 | |||
126 | result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, | ||
127 | WDRTAS_SP_SPI, (void *)__pa(&value), 4); | ||
128 | if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) || | ||
129 | (result < 0) ) { | ||
130 | printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " | ||
131 | "timeout (%li). Continuing\n", result); | ||
132 | return fallback_value; | ||
133 | } | ||
134 | |||
135 | /* rtas uses minutes */ | ||
136 | return ((int)value[2]) * 60; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * wdrtas_timer_start - starts watchdog | ||
141 | * | ||
142 | * wdrtas_timer_start starts the watchdog by calling the RTAS function | ||
143 | * set-interval (surveillance) | ||
144 | */ | ||
145 | static void | ||
146 | wdrtas_timer_start(void) | ||
147 | { | ||
148 | wdrtas_set_interval(wdrtas_interval); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * wdrtas_timer_stop - stops watchdog | ||
153 | * | ||
154 | * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function | ||
155 | * set-interval (surveillance) | ||
156 | */ | ||
157 | static void | ||
158 | wdrtas_timer_stop(void) | ||
159 | { | ||
160 | wdrtas_set_interval(0); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * wdrtas_log_scanned_event - logs an event we received during keepalive | ||
165 | * | ||
166 | * wdrtas_log_scanned_event prints a message to the log buffer dumping | ||
167 | * the results of the last event-scan call | ||
168 | */ | ||
169 | static void | ||
170 | wdrtas_log_scanned_event(void) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16) | ||
175 | printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = " | ||
176 | "%02x %02x %02x %02x %02x %02x %02x %02x " | ||
177 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
178 | (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), | ||
179 | wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], | ||
180 | wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], | ||
181 | wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], | ||
182 | wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], | ||
183 | wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], | ||
184 | wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], | ||
185 | wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], | ||
186 | wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * wdrtas_timer_keepalive - resets watchdog timer to keep system alive | ||
191 | * | ||
192 | * wdrtas_timer_keepalive restarts the watchdog timer by calling the | ||
193 | * RTAS function event-scan and repeats these calls as long as there are | ||
194 | * events available. All events will be dumped. | ||
195 | */ | ||
196 | static void | ||
197 | wdrtas_timer_keepalive(void) | ||
198 | { | ||
199 | long result; | ||
200 | |||
201 | do { | ||
202 | result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL, | ||
203 | RTAS_EVENT_SCAN_ALL_EVENTS, 0, | ||
204 | (void *)__pa(wdrtas_logbuffer), | ||
205 | WDRTAS_LOGBUFFER_LEN); | ||
206 | if (result < 0) | ||
207 | printk(KERN_ERR "wdrtas: event-scan failed: %li\n", | ||
208 | result); | ||
209 | if (result == 0) | ||
210 | wdrtas_log_scanned_event(); | ||
211 | } while (result == 0); | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * wdrtas_get_temperature - returns current temperature | ||
216 | * | ||
217 | * returns temperature or <0 on failures | ||
218 | * | ||
219 | * wdrtas_get_temperature returns the current temperature in Fahrenheit. It | ||
220 | * uses the RTAS call get-sensor-state, token 3 to do so | ||
221 | */ | ||
222 | static int | ||
223 | wdrtas_get_temperature(void) | ||
224 | { | ||
225 | long result; | ||
226 | int temperature = 0; | ||
227 | |||
228 | result = rtas_call(wdrtas_token_get_sensor_state, 2, 2, | ||
229 | (void *)__pa(&temperature), | ||
230 | WDRTAS_THERMAL_SENSOR, 0); | ||
231 | |||
232 | if (result < 0) | ||
233 | printk(KERN_WARNING "wdrtas: reading the thermal sensor " | ||
234 | "faild: %li\n", result); | ||
235 | else | ||
236 | temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */ | ||
237 | |||
238 | return temperature; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * wdrtas_get_status - returns the status of the watchdog | ||
243 | * | ||
244 | * returns a bitmask of defines WDIOF_... as defined in | ||
245 | * include/linux/watchdog.h | ||
246 | */ | ||
247 | static int | ||
248 | wdrtas_get_status(void) | ||
249 | { | ||
250 | return 0; /* TODO */ | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * wdrtas_get_boot_status - returns the reason for the last boot | ||
255 | * | ||
256 | * returns a bitmask of defines WDIOF_... as defined in | ||
257 | * include/linux/watchdog.h, indicating why the watchdog rebooted the system | ||
258 | */ | ||
259 | static int | ||
260 | wdrtas_get_boot_status(void) | ||
261 | { | ||
262 | return 0; /* TODO */ | ||
263 | } | ||
264 | |||
265 | /*** watchdog API and operations stuff */ | ||
266 | |||
267 | /* wdrtas_write - called when watchdog device is written to | ||
268 | * @file: file structure | ||
269 | * @buf: user buffer with data | ||
270 | * @len: amount to data written | ||
271 | * @ppos: position in file | ||
272 | * | ||
273 | * returns the number of successfully processed characters, which is always | ||
274 | * the number of bytes passed to this function | ||
275 | * | ||
276 | * wdrtas_write processes all the data given to it and looks for the magic | ||
277 | * character 'V'. This character allows the watchdog device to be closed | ||
278 | * properly. | ||
279 | */ | ||
280 | static ssize_t | ||
281 | wdrtas_write(struct file *file, const char __user *buf, | ||
282 | size_t len, loff_t *ppos) | ||
283 | { | ||
284 | int i; | ||
285 | char c; | ||
286 | |||
287 | if (!len) | ||
288 | goto out; | ||
289 | |||
290 | if (!wdrtas_nowayout) { | ||
291 | wdrtas_expect_close = 0; | ||
292 | /* look for 'V' */ | ||
293 | for (i = 0; i < len; i++) { | ||
294 | if (get_user(c, buf + i)) | ||
295 | return -EFAULT; | ||
296 | /* allow to close device */ | ||
297 | if (c == 'V') | ||
298 | wdrtas_expect_close = WDRTAS_MAGIC_CHAR; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | wdrtas_timer_keepalive(); | ||
303 | |||
304 | out: | ||
305 | return len; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * wdrtas_ioctl - ioctl function for the watchdog device | ||
310 | * @inode: inode structure | ||
311 | * @file: file structure | ||
312 | * @cmd: command for ioctl | ||
313 | * @arg: argument pointer | ||
314 | * | ||
315 | * returns 0 on success, <0 on failure | ||
316 | * | ||
317 | * wdrtas_ioctl implements the watchdog API ioctls | ||
318 | */ | ||
319 | static int | ||
320 | wdrtas_ioctl(struct inode *inode, struct file *file, | ||
321 | unsigned int cmd, unsigned long arg) | ||
322 | { | ||
323 | int __user *argp = (void *)arg; | ||
324 | int i; | ||
325 | static struct watchdog_info wdinfo = { | ||
326 | .options = WDRTAS_SUPPORTED_MASK, | ||
327 | .firmware_version = 0, | ||
328 | .identity = "wdrtas" | ||
329 | }; | ||
330 | |||
331 | switch (cmd) { | ||
332 | case WDIOC_GETSUPPORT: | ||
333 | if (copy_to_user(argp, &wdinfo, sizeof(wdinfo))) | ||
334 | return -EFAULT; | ||
335 | return 0; | ||
336 | |||
337 | case WDIOC_GETSTATUS: | ||
338 | i = wdrtas_get_status(); | ||
339 | return put_user(i, argp); | ||
340 | |||
341 | case WDIOC_GETBOOTSTATUS: | ||
342 | i = wdrtas_get_boot_status(); | ||
343 | return put_user(i, argp); | ||
344 | |||
345 | case WDIOC_GETTEMP: | ||
346 | if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) | ||
347 | return -EOPNOTSUPP; | ||
348 | |||
349 | i = wdrtas_get_temperature(); | ||
350 | return put_user(i, argp); | ||
351 | |||
352 | case WDIOC_SETOPTIONS: | ||
353 | if (get_user(i, argp)) | ||
354 | return -EFAULT; | ||
355 | if (i & WDIOS_DISABLECARD) | ||
356 | wdrtas_timer_stop(); | ||
357 | if (i & WDIOS_ENABLECARD) { | ||
358 | wdrtas_timer_keepalive(); | ||
359 | wdrtas_timer_start(); | ||
360 | } | ||
361 | if (i & WDIOS_TEMPPANIC) { | ||
362 | /* not implemented. Done by H8 */ | ||
363 | } | ||
364 | return 0; | ||
365 | |||
366 | case WDIOC_KEEPALIVE: | ||
367 | wdrtas_timer_keepalive(); | ||
368 | return 0; | ||
369 | |||
370 | case WDIOC_SETTIMEOUT: | ||
371 | if (get_user(i, argp)) | ||
372 | return -EFAULT; | ||
373 | |||
374 | if (wdrtas_set_interval(i)) | ||
375 | return -EINVAL; | ||
376 | |||
377 | wdrtas_timer_keepalive(); | ||
378 | |||
379 | if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) | ||
380 | wdrtas_interval = i; | ||
381 | else | ||
382 | wdrtas_interval = wdrtas_get_interval(i); | ||
383 | /* fallthrough */ | ||
384 | |||
385 | case WDIOC_GETTIMEOUT: | ||
386 | return put_user(wdrtas_interval, argp); | ||
387 | |||
388 | default: | ||
389 | return -ENOIOCTLCMD; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * wdrtas_open - open function of watchdog device | ||
395 | * @inode: inode structure | ||
396 | * @file: file structure | ||
397 | * | ||
398 | * returns 0 on success, -EBUSY if the file has been opened already, <0 on | ||
399 | * other failures | ||
400 | * | ||
401 | * function called when watchdog device is opened | ||
402 | */ | ||
403 | static int | ||
404 | wdrtas_open(struct inode *inode, struct file *file) | ||
405 | { | ||
406 | /* only open once */ | ||
407 | if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { | ||
408 | atomic_dec(&wdrtas_miscdev_open); | ||
409 | return -EBUSY; | ||
410 | } | ||
411 | |||
412 | wdrtas_timer_start(); | ||
413 | wdrtas_timer_keepalive(); | ||
414 | |||
415 | return nonseekable_open(inode, file); | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * wdrtas_close - close function of watchdog device | ||
420 | * @inode: inode structure | ||
421 | * @file: file structure | ||
422 | * | ||
423 | * returns 0 on success | ||
424 | * | ||
425 | * close function. Always succeeds | ||
426 | */ | ||
427 | static int | ||
428 | wdrtas_close(struct inode *inode, struct file *file) | ||
429 | { | ||
430 | /* only stop watchdog, if this was announced using 'V' before */ | ||
431 | if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) | ||
432 | wdrtas_timer_stop(); | ||
433 | else { | ||
434 | printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog " | ||
435 | "not stopped.\n"); | ||
436 | wdrtas_timer_keepalive(); | ||
437 | } | ||
438 | |||
439 | wdrtas_expect_close = 0; | ||
440 | atomic_dec(&wdrtas_miscdev_open); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * wdrtas_temp_read - gives back the temperature in fahrenheit | ||
446 | * @file: file structure | ||
447 | * @buf: user buffer | ||
448 | * @count: number of bytes to be read | ||
449 | * @ppos: position in file | ||
450 | * | ||
451 | * returns always 1 or -EFAULT in case of user space copy failures, <0 on | ||
452 | * other failures | ||
453 | * | ||
454 | * wdrtas_temp_read gives the temperature to the users by copying this | ||
455 | * value as one byte into the user space buffer. The unit is Fahrenheit... | ||
456 | */ | ||
457 | static ssize_t | ||
458 | wdrtas_temp_read(struct file *file, char __user *buf, | ||
459 | size_t count, loff_t *ppos) | ||
460 | { | ||
461 | int temperature = 0; | ||
462 | |||
463 | temperature = wdrtas_get_temperature(); | ||
464 | if (temperature < 0) | ||
465 | return temperature; | ||
466 | |||
467 | if (copy_to_user(buf, &temperature, 1)) | ||
468 | return -EFAULT; | ||
469 | |||
470 | return 1; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * wdrtas_temp_open - open function of temperature device | ||
475 | * @inode: inode structure | ||
476 | * @file: file structure | ||
477 | * | ||
478 | * returns 0 on success, <0 on failure | ||
479 | * | ||
480 | * function called when temperature device is opened | ||
481 | */ | ||
482 | static int | ||
483 | wdrtas_temp_open(struct inode *inode, struct file *file) | ||
484 | { | ||
485 | return nonseekable_open(inode, file); | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * wdrtas_temp_close - close function of temperature device | ||
490 | * @inode: inode structure | ||
491 | * @file: file structure | ||
492 | * | ||
493 | * returns 0 on success | ||
494 | * | ||
495 | * close function. Always succeeds | ||
496 | */ | ||
497 | static int | ||
498 | wdrtas_temp_close(struct inode *inode, struct file *file) | ||
499 | { | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | /** | ||
504 | * wdrtas_reboot - reboot notifier function | ||
505 | * @nb: notifier block structure | ||
506 | * @code: reboot code | ||
507 | * @ptr: unused | ||
508 | * | ||
509 | * returns NOTIFY_DONE | ||
510 | * | ||
511 | * wdrtas_reboot stops the watchdog in case of a reboot | ||
512 | */ | ||
513 | static int | ||
514 | wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr) | ||
515 | { | ||
516 | if ( (code==SYS_DOWN) || (code==SYS_HALT) ) | ||
517 | wdrtas_timer_stop(); | ||
518 | |||
519 | return NOTIFY_DONE; | ||
520 | } | ||
521 | |||
522 | /*** initialization stuff */ | ||
523 | |||
524 | static struct file_operations wdrtas_fops = { | ||
525 | .owner = THIS_MODULE, | ||
526 | .llseek = no_llseek, | ||
527 | .write = wdrtas_write, | ||
528 | .ioctl = wdrtas_ioctl, | ||
529 | .open = wdrtas_open, | ||
530 | .release = wdrtas_close, | ||
531 | }; | ||
532 | |||
533 | static struct miscdevice wdrtas_miscdev = { | ||
534 | .minor = WATCHDOG_MINOR, | ||
535 | .name = "watchdog", | ||
536 | .fops = &wdrtas_fops, | ||
537 | }; | ||
538 | |||
539 | static struct file_operations wdrtas_temp_fops = { | ||
540 | .owner = THIS_MODULE, | ||
541 | .llseek = no_llseek, | ||
542 | .read = wdrtas_temp_read, | ||
543 | .open = wdrtas_temp_open, | ||
544 | .release = wdrtas_temp_close, | ||
545 | }; | ||
546 | |||
547 | static struct miscdevice wdrtas_tempdev = { | ||
548 | .minor = TEMP_MINOR, | ||
549 | .name = "temperature", | ||
550 | .fops = &wdrtas_temp_fops, | ||
551 | }; | ||
552 | |||
553 | static struct notifier_block wdrtas_notifier = { | ||
554 | .notifier_call = wdrtas_reboot, | ||
555 | }; | ||
556 | |||
557 | /** | ||
558 | * wdrtas_get_tokens - reads in RTAS tokens | ||
559 | * | ||
560 | * returns 0 on succes, <0 on failure | ||
561 | * | ||
562 | * wdrtas_get_tokens reads in the tokens for the RTAS calls used in | ||
563 | * this watchdog driver. It tolerates, if "get-sensor-state" and | ||
564 | * "ibm,get-system-parameter" are not available. | ||
565 | */ | ||
566 | static int | ||
567 | wdrtas_get_tokens(void) | ||
568 | { | ||
569 | wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); | ||
570 | if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { | ||
571 | printk(KERN_WARNING "wdrtas: couldn't get token for " | ||
572 | "get-sensor-state. Trying to continue without " | ||
573 | "temperature support.\n"); | ||
574 | } | ||
575 | |||
576 | wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter"); | ||
577 | if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) { | ||
578 | printk(KERN_WARNING "wdrtas: couldn't get token for " | ||
579 | "ibm,get-system-parameter. Trying to continue with " | ||
580 | "a default timeout value of %i seconds.\n", | ||
581 | WDRTAS_DEFAULT_INTERVAL); | ||
582 | } | ||
583 | |||
584 | wdrtas_token_set_indicator = rtas_token("set-indicator"); | ||
585 | if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) { | ||
586 | printk(KERN_ERR "wdrtas: couldn't get token for " | ||
587 | "set-indicator. Terminating watchdog code.\n"); | ||
588 | return -EIO; | ||
589 | } | ||
590 | |||
591 | wdrtas_token_event_scan = rtas_token("event-scan"); | ||
592 | if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) { | ||
593 | printk(KERN_ERR "wdrtas: couldn't get token for event-scan. " | ||
594 | "Terminating watchdog code.\n"); | ||
595 | return -EIO; | ||
596 | } | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * wdrtas_unregister_devs - unregisters the misc dev handlers | ||
603 | * | ||
604 | * wdrtas_register_devs unregisters the watchdog and temperature watchdog | ||
605 | * misc devs | ||
606 | */ | ||
607 | static void | ||
608 | wdrtas_unregister_devs(void) | ||
609 | { | ||
610 | misc_deregister(&wdrtas_miscdev); | ||
611 | if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) | ||
612 | misc_deregister(&wdrtas_tempdev); | ||
613 | } | ||
614 | |||
615 | /** | ||
616 | * wdrtas_register_devs - registers the misc dev handlers | ||
617 | * | ||
618 | * returns 0 on succes, <0 on failure | ||
619 | * | ||
620 | * wdrtas_register_devs registers the watchdog and temperature watchdog | ||
621 | * misc devs | ||
622 | */ | ||
623 | static int | ||
624 | wdrtas_register_devs(void) | ||
625 | { | ||
626 | int result; | ||
627 | |||
628 | result = misc_register(&wdrtas_miscdev); | ||
629 | if (result) { | ||
630 | printk(KERN_ERR "wdrtas: couldn't register watchdog misc " | ||
631 | "device. Terminating watchdog code.\n"); | ||
632 | return result; | ||
633 | } | ||
634 | |||
635 | if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) { | ||
636 | result = misc_register(&wdrtas_tempdev); | ||
637 | if (result) { | ||
638 | printk(KERN_WARNING "wdrtas: couldn't register " | ||
639 | "watchdog temperature misc device. Continuing " | ||
640 | "without temperature support.\n"); | ||
641 | wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * wdrtas_init - init function of the watchdog driver | ||
650 | * | ||
651 | * returns 0 on succes, <0 on failure | ||
652 | * | ||
653 | * registers the file handlers and the reboot notifier | ||
654 | */ | ||
655 | static int __init | ||
656 | wdrtas_init(void) | ||
657 | { | ||
658 | if (wdrtas_get_tokens()) | ||
659 | return -ENODEV; | ||
660 | |||
661 | if (wdrtas_register_devs()) | ||
662 | return -ENODEV; | ||
663 | |||
664 | if (register_reboot_notifier(&wdrtas_notifier)) { | ||
665 | printk(KERN_ERR "wdrtas: could not register reboot notifier. " | ||
666 | "Terminating watchdog code.\n"); | ||
667 | wdrtas_unregister_devs(); | ||
668 | return -ENODEV; | ||
669 | } | ||
670 | |||
671 | if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) | ||
672 | wdrtas_interval = WDRTAS_DEFAULT_INTERVAL; | ||
673 | else | ||
674 | wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * wdrtas_exit - exit function of the watchdog driver | ||
681 | * | ||
682 | * unregisters the file handlers and the reboot notifier | ||
683 | */ | ||
684 | static void __exit | ||
685 | wdrtas_exit(void) | ||
686 | { | ||
687 | if (!wdrtas_nowayout) | ||
688 | wdrtas_timer_stop(); | ||
689 | |||
690 | wdrtas_unregister_devs(); | ||
691 | |||
692 | unregister_reboot_notifier(&wdrtas_notifier); | ||
693 | } | ||
694 | |||
695 | module_init(wdrtas_init); | ||
696 | module_exit(wdrtas_exit); | ||