diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/i8k.c | 950 |
1 files changed, 475 insertions, 475 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index a81197640283..bf5e43beca62 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c | |||
@@ -55,14 +55,14 @@ | |||
55 | #define DELL_SIGNATURE "Dell Computer" | 55 | #define DELL_SIGNATURE "Dell Computer" |
56 | 56 | ||
57 | static char *supported_models[] = { | 57 | static char *supported_models[] = { |
58 | "Inspiron", | 58 | "Inspiron", |
59 | "Latitude", | 59 | "Latitude", |
60 | NULL | 60 | NULL |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static char system_vendor[48] = "?"; | 63 | static char system_vendor[48] = "?"; |
64 | static char product_name [48] = "?"; | 64 | static char product_name[48] = "?"; |
65 | static char bios_version [4] = "?"; | 65 | static char bios_version[4] = "?"; |
66 | static char serial_number[16] = "?"; | 66 | static char serial_number[16] = "?"; |
67 | 67 | ||
68 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); | 68 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); |
@@ -86,64 +86,63 @@ static int i8k_ioctl(struct inode *, struct file *, unsigned int, | |||
86 | unsigned long); | 86 | unsigned long); |
87 | 87 | ||
88 | static struct file_operations i8k_fops = { | 88 | static struct file_operations i8k_fops = { |
89 | .read = i8k_read, | 89 | .read = i8k_read, |
90 | .ioctl = i8k_ioctl, | 90 | .ioctl = i8k_ioctl, |
91 | }; | 91 | }; |
92 | 92 | ||
93 | typedef struct { | 93 | typedef struct { |
94 | unsigned int eax; | 94 | unsigned int eax; |
95 | unsigned int ebx __attribute__ ((packed)); | 95 | unsigned int ebx __attribute__ ((packed)); |
96 | unsigned int ecx __attribute__ ((packed)); | 96 | unsigned int ecx __attribute__ ((packed)); |
97 | unsigned int edx __attribute__ ((packed)); | 97 | unsigned int edx __attribute__ ((packed)); |
98 | unsigned int esi __attribute__ ((packed)); | 98 | unsigned int esi __attribute__ ((packed)); |
99 | unsigned int edi __attribute__ ((packed)); | 99 | unsigned int edi __attribute__ ((packed)); |
100 | } SMMRegisters; | 100 | } SMMRegisters; |
101 | 101 | ||
102 | typedef struct { | 102 | typedef struct { |
103 | u8 type; | 103 | u8 type; |
104 | u8 length; | 104 | u8 length; |
105 | u16 handle; | 105 | u16 handle; |
106 | } DMIHeader; | 106 | } DMIHeader; |
107 | 107 | ||
108 | /* | 108 | /* |
109 | * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. | 109 | * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. |
110 | */ | 110 | */ |
111 | static int i8k_smm(SMMRegisters *regs) | 111 | static int i8k_smm(SMMRegisters * regs) |
112 | { | 112 | { |
113 | int rc; | 113 | int rc; |
114 | int eax = regs->eax; | 114 | int eax = regs->eax; |
115 | 115 | ||
116 | asm("pushl %%eax\n\t" \ | 116 | asm("pushl %%eax\n\t" |
117 | "movl 0(%%eax),%%edx\n\t" \ | 117 | "movl 0(%%eax),%%edx\n\t" |
118 | "push %%edx\n\t" \ | 118 | "push %%edx\n\t" |
119 | "movl 4(%%eax),%%ebx\n\t" \ | 119 | "movl 4(%%eax),%%ebx\n\t" |
120 | "movl 8(%%eax),%%ecx\n\t" \ | 120 | "movl 8(%%eax),%%ecx\n\t" |
121 | "movl 12(%%eax),%%edx\n\t" \ | 121 | "movl 12(%%eax),%%edx\n\t" |
122 | "movl 16(%%eax),%%esi\n\t" \ | 122 | "movl 16(%%eax),%%esi\n\t" |
123 | "movl 20(%%eax),%%edi\n\t" \ | 123 | "movl 20(%%eax),%%edi\n\t" |
124 | "popl %%eax\n\t" \ | 124 | "popl %%eax\n\t" |
125 | "out %%al,$0xb2\n\t" \ | 125 | "out %%al,$0xb2\n\t" |
126 | "out %%al,$0x84\n\t" \ | 126 | "out %%al,$0x84\n\t" |
127 | "xchgl %%eax,(%%esp)\n\t" | 127 | "xchgl %%eax,(%%esp)\n\t" |
128 | "movl %%ebx,4(%%eax)\n\t" \ | 128 | "movl %%ebx,4(%%eax)\n\t" |
129 | "movl %%ecx,8(%%eax)\n\t" \ | 129 | "movl %%ecx,8(%%eax)\n\t" |
130 | "movl %%edx,12(%%eax)\n\t" \ | 130 | "movl %%edx,12(%%eax)\n\t" |
131 | "movl %%esi,16(%%eax)\n\t" \ | 131 | "movl %%esi,16(%%eax)\n\t" |
132 | "movl %%edi,20(%%eax)\n\t" \ | 132 | "movl %%edi,20(%%eax)\n\t" |
133 | "popl %%edx\n\t" \ | 133 | "popl %%edx\n\t" |
134 | "movl %%edx,0(%%eax)\n\t" \ | 134 | "movl %%edx,0(%%eax)\n\t" |
135 | "lahf\n\t" \ | 135 | "lahf\n\t" |
136 | "shrl $8,%%eax\n\t" \ | 136 | "shrl $8,%%eax\n\t" |
137 | "andl $1,%%eax\n" \ | 137 | "andl $1,%%eax\n":"=a"(rc) |
138 | : "=a" (rc) | 138 | : "a"(regs) |
139 | : "a" (regs) | 139 | : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); |
140 | : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); | 140 | |
141 | 141 | if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { | |
142 | if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { | 142 | return -EINVAL; |
143 | return -EINVAL; | 143 | } |
144 | } | 144 | |
145 | 145 | return 0; | |
146 | return 0; | ||
147 | } | 146 | } |
148 | 147 | ||
149 | /* | 148 | /* |
@@ -152,15 +151,15 @@ static int i8k_smm(SMMRegisters *regs) | |||
152 | */ | 151 | */ |
153 | static int i8k_get_bios_version(void) | 152 | static int i8k_get_bios_version(void) |
154 | { | 153 | { |
155 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 154 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
156 | int rc; | 155 | int rc; |
157 | 156 | ||
158 | regs.eax = I8K_SMM_BIOS_VERSION; | 157 | regs.eax = I8K_SMM_BIOS_VERSION; |
159 | if ((rc=i8k_smm(®s)) < 0) { | 158 | if ((rc = i8k_smm(®s)) < 0) { |
160 | return rc; | 159 | return rc; |
161 | } | 160 | } |
162 | 161 | ||
163 | return regs.eax; | 162 | return regs.eax; |
164 | } | 163 | } |
165 | 164 | ||
166 | /* | 165 | /* |
@@ -168,8 +167,8 @@ static int i8k_get_bios_version(void) | |||
168 | */ | 167 | */ |
169 | static int i8k_get_serial_number(unsigned char *buff) | 168 | static int i8k_get_serial_number(unsigned char *buff) |
170 | { | 169 | { |
171 | strlcpy(buff, serial_number, sizeof(serial_number)); | 170 | strlcpy(buff, serial_number, sizeof(serial_number)); |
172 | return 0; | 171 | return 0; |
173 | } | 172 | } |
174 | 173 | ||
175 | /* | 174 | /* |
@@ -177,24 +176,24 @@ static int i8k_get_serial_number(unsigned char *buff) | |||
177 | */ | 176 | */ |
178 | static int i8k_get_fn_status(void) | 177 | static int i8k_get_fn_status(void) |
179 | { | 178 | { |
180 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 179 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
181 | int rc; | 180 | int rc; |
182 | 181 | ||
183 | regs.eax = I8K_SMM_FN_STATUS; | 182 | regs.eax = I8K_SMM_FN_STATUS; |
184 | if ((rc=i8k_smm(®s)) < 0) { | 183 | if ((rc = i8k_smm(®s)) < 0) { |
185 | return rc; | 184 | return rc; |
186 | } | 185 | } |
187 | 186 | ||
188 | switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { | 187 | switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { |
189 | case I8K_FN_UP: | 188 | case I8K_FN_UP: |
190 | return I8K_VOL_UP; | 189 | return I8K_VOL_UP; |
191 | case I8K_FN_DOWN: | 190 | case I8K_FN_DOWN: |
192 | return I8K_VOL_DOWN; | 191 | return I8K_VOL_DOWN; |
193 | case I8K_FN_MUTE: | 192 | case I8K_FN_MUTE: |
194 | return I8K_VOL_MUTE; | 193 | return I8K_VOL_MUTE; |
195 | default: | 194 | default: |
196 | return 0; | 195 | return 0; |
197 | } | 196 | } |
198 | } | 197 | } |
199 | 198 | ||
200 | /* | 199 | /* |
@@ -202,20 +201,20 @@ static int i8k_get_fn_status(void) | |||
202 | */ | 201 | */ |
203 | static int i8k_get_power_status(void) | 202 | static int i8k_get_power_status(void) |
204 | { | 203 | { |
205 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 204 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
206 | int rc; | 205 | int rc; |
207 | 206 | ||
208 | regs.eax = I8K_SMM_POWER_STATUS; | 207 | regs.eax = I8K_SMM_POWER_STATUS; |
209 | if ((rc=i8k_smm(®s)) < 0) { | 208 | if ((rc = i8k_smm(®s)) < 0) { |
210 | return rc; | 209 | return rc; |
211 | } | 210 | } |
212 | 211 | ||
213 | switch (regs.eax & 0xff) { | 212 | switch (regs.eax & 0xff) { |
214 | case I8K_POWER_AC: | 213 | case I8K_POWER_AC: |
215 | return I8K_AC; | 214 | return I8K_AC; |
216 | default: | 215 | default: |
217 | return I8K_BATTERY; | 216 | return I8K_BATTERY; |
218 | } | 217 | } |
219 | } | 218 | } |
220 | 219 | ||
221 | /* | 220 | /* |
@@ -223,16 +222,16 @@ static int i8k_get_power_status(void) | |||
223 | */ | 222 | */ |
224 | static int i8k_get_fan_status(int fan) | 223 | static int i8k_get_fan_status(int fan) |
225 | { | 224 | { |
226 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 225 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
227 | int rc; | 226 | int rc; |
228 | 227 | ||
229 | regs.eax = I8K_SMM_GET_FAN; | 228 | regs.eax = I8K_SMM_GET_FAN; |
230 | regs.ebx = fan & 0xff; | 229 | regs.ebx = fan & 0xff; |
231 | if ((rc=i8k_smm(®s)) < 0) { | 230 | if ((rc = i8k_smm(®s)) < 0) { |
232 | return rc; | 231 | return rc; |
233 | } | 232 | } |
234 | 233 | ||
235 | return (regs.eax & 0xff); | 234 | return (regs.eax & 0xff); |
236 | } | 235 | } |
237 | 236 | ||
238 | /* | 237 | /* |
@@ -240,16 +239,16 @@ static int i8k_get_fan_status(int fan) | |||
240 | */ | 239 | */ |
241 | static int i8k_get_fan_speed(int fan) | 240 | static int i8k_get_fan_speed(int fan) |
242 | { | 241 | { |
243 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 242 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
244 | int rc; | 243 | int rc; |
245 | 244 | ||
246 | regs.eax = I8K_SMM_GET_SPEED; | 245 | regs.eax = I8K_SMM_GET_SPEED; |
247 | regs.ebx = fan & 0xff; | 246 | regs.ebx = fan & 0xff; |
248 | if ((rc=i8k_smm(®s)) < 0) { | 247 | if ((rc = i8k_smm(®s)) < 0) { |
249 | return rc; | 248 | return rc; |
250 | } | 249 | } |
251 | 250 | ||
252 | return (regs.eax & 0xffff) * I8K_FAN_MULT; | 251 | return (regs.eax & 0xffff) * I8K_FAN_MULT; |
253 | } | 252 | } |
254 | 253 | ||
255 | /* | 254 | /* |
@@ -257,18 +256,18 @@ static int i8k_get_fan_speed(int fan) | |||
257 | */ | 256 | */ |
258 | static int i8k_set_fan(int fan, int speed) | 257 | static int i8k_set_fan(int fan, int speed) |
259 | { | 258 | { |
260 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 259 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
261 | int rc; | 260 | int rc; |
262 | 261 | ||
263 | speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); | 262 | speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); |
264 | 263 | ||
265 | regs.eax = I8K_SMM_SET_FAN; | 264 | regs.eax = I8K_SMM_SET_FAN; |
266 | regs.ebx = (fan & 0xff) | (speed << 8); | 265 | regs.ebx = (fan & 0xff) | (speed << 8); |
267 | if ((rc=i8k_smm(®s)) < 0) { | 266 | if ((rc = i8k_smm(®s)) < 0) { |
268 | return rc; | 267 | return rc; |
269 | } | 268 | } |
270 | 269 | ||
271 | return (i8k_get_fan_status(fan)); | 270 | return (i8k_get_fan_status(fan)); |
272 | } | 271 | } |
273 | 272 | ||
274 | /* | 273 | /* |
@@ -276,143 +275,143 @@ static int i8k_set_fan(int fan, int speed) | |||
276 | */ | 275 | */ |
277 | static int i8k_get_cpu_temp(void) | 276 | static int i8k_get_cpu_temp(void) |
278 | { | 277 | { |
279 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 278 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
280 | int rc; | 279 | int rc; |
281 | int temp; | 280 | int temp; |
282 | 281 | ||
283 | #ifdef I8K_TEMPERATURE_BUG | 282 | #ifdef I8K_TEMPERATURE_BUG |
284 | static int prev = 0; | 283 | static int prev = 0; |
285 | #endif | 284 | #endif |
286 | 285 | ||
287 | regs.eax = I8K_SMM_GET_TEMP; | 286 | regs.eax = I8K_SMM_GET_TEMP; |
288 | if ((rc=i8k_smm(®s)) < 0) { | 287 | if ((rc = i8k_smm(®s)) < 0) { |
289 | return rc; | 288 | return rc; |
290 | } | 289 | } |
291 | temp = regs.eax & 0xff; | 290 | temp = regs.eax & 0xff; |
292 | 291 | ||
293 | #ifdef I8K_TEMPERATURE_BUG | 292 | #ifdef I8K_TEMPERATURE_BUG |
294 | /* | 293 | /* |
295 | * Sometimes the temperature sensor returns 0x99, which is out of range. | 294 | * Sometimes the temperature sensor returns 0x99, which is out of range. |
296 | * In this case we return (once) the previous cached value. For example: | 295 | * In this case we return (once) the previous cached value. For example: |
297 | # 1003655137 00000058 00005a4b | 296 | # 1003655137 00000058 00005a4b |
298 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees | 297 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees |
299 | # 1003655139 00000054 00005c52 | 298 | # 1003655139 00000054 00005c52 |
300 | */ | 299 | */ |
301 | if (temp > I8K_MAX_TEMP) { | 300 | if (temp > I8K_MAX_TEMP) { |
302 | temp = prev; | 301 | temp = prev; |
303 | prev = I8K_MAX_TEMP; | 302 | prev = I8K_MAX_TEMP; |
304 | } else { | 303 | } else { |
305 | prev = temp; | 304 | prev = temp; |
306 | } | 305 | } |
307 | #endif | 306 | #endif |
308 | 307 | ||
309 | return temp; | 308 | return temp; |
310 | } | 309 | } |
311 | 310 | ||
312 | static int i8k_get_dell_signature(void) | 311 | static int i8k_get_dell_signature(void) |
313 | { | 312 | { |
314 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; | 313 | SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; |
315 | int rc; | 314 | int rc; |
316 | 315 | ||
317 | regs.eax = I8K_SMM_GET_DELL_SIG; | 316 | regs.eax = I8K_SMM_GET_DELL_SIG; |
318 | if ((rc=i8k_smm(®s)) < 0) { | 317 | if ((rc = i8k_smm(®s)) < 0) { |
319 | return rc; | 318 | return rc; |
320 | } | 319 | } |
321 | 320 | ||
322 | if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { | 321 | if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { |
323 | return 0; | 322 | return 0; |
324 | } else { | 323 | } else { |
325 | return -1; | 324 | return -1; |
326 | } | 325 | } |
327 | } | 326 | } |
328 | 327 | ||
329 | static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | 328 | static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, |
330 | unsigned long arg) | 329 | unsigned long arg) |
331 | { | 330 | { |
332 | int val; | 331 | int val; |
333 | int speed; | 332 | int speed; |
334 | unsigned char buff[16]; | 333 | unsigned char buff[16]; |
335 | int __user *argp = (int __user *)arg; | 334 | int __user *argp = (int __user *)arg; |
336 | 335 | ||
337 | if (!argp) | 336 | if (!argp) |
338 | return -EINVAL; | 337 | return -EINVAL; |
339 | 338 | ||
340 | switch (cmd) { | 339 | switch (cmd) { |
341 | case I8K_BIOS_VERSION: | 340 | case I8K_BIOS_VERSION: |
342 | val = i8k_get_bios_version(); | 341 | val = i8k_get_bios_version(); |
343 | break; | 342 | break; |
344 | 343 | ||
345 | case I8K_MACHINE_ID: | 344 | case I8K_MACHINE_ID: |
346 | memset(buff, 0, 16); | 345 | memset(buff, 0, 16); |
347 | val = i8k_get_serial_number(buff); | 346 | val = i8k_get_serial_number(buff); |
348 | break; | 347 | break; |
349 | 348 | ||
350 | case I8K_FN_STATUS: | 349 | case I8K_FN_STATUS: |
351 | val = i8k_get_fn_status(); | 350 | val = i8k_get_fn_status(); |
352 | break; | 351 | break; |
353 | 352 | ||
354 | case I8K_POWER_STATUS: | 353 | case I8K_POWER_STATUS: |
355 | val = i8k_get_power_status(); | 354 | val = i8k_get_power_status(); |
356 | break; | 355 | break; |
356 | |||
357 | case I8K_GET_TEMP: | ||
358 | val = i8k_get_cpu_temp(); | ||
359 | break; | ||
360 | |||
361 | case I8K_GET_SPEED: | ||
362 | if (copy_from_user(&val, argp, sizeof(int))) { | ||
363 | return -EFAULT; | ||
364 | } | ||
365 | val = i8k_get_fan_speed(val); | ||
366 | break; | ||
357 | 367 | ||
358 | case I8K_GET_TEMP: | 368 | case I8K_GET_FAN: |
359 | val = i8k_get_cpu_temp(); | 369 | if (copy_from_user(&val, argp, sizeof(int))) { |
360 | break; | 370 | return -EFAULT; |
371 | } | ||
372 | val = i8k_get_fan_status(val); | ||
373 | break; | ||
361 | 374 | ||
362 | case I8K_GET_SPEED: | 375 | case I8K_SET_FAN: |
363 | if (copy_from_user(&val, argp, sizeof(int))) { | 376 | if (restricted && !capable(CAP_SYS_ADMIN)) { |
364 | return -EFAULT; | 377 | return -EPERM; |
365 | } | 378 | } |
366 | val = i8k_get_fan_speed(val); | 379 | if (copy_from_user(&val, argp, sizeof(int))) { |
367 | break; | 380 | return -EFAULT; |
381 | } | ||
382 | if (copy_from_user(&speed, argp + 1, sizeof(int))) { | ||
383 | return -EFAULT; | ||
384 | } | ||
385 | val = i8k_set_fan(val, speed); | ||
386 | break; | ||
368 | 387 | ||
369 | case I8K_GET_FAN: | 388 | default: |
370 | if (copy_from_user(&val, argp, sizeof(int))) { | 389 | return -EINVAL; |
371 | return -EFAULT; | ||
372 | } | 390 | } |
373 | val = i8k_get_fan_status(val); | ||
374 | break; | ||
375 | 391 | ||
376 | case I8K_SET_FAN: | 392 | if (val < 0) { |
377 | if (restricted && !capable(CAP_SYS_ADMIN)) { | 393 | return val; |
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 | } | 394 | } |
386 | val = i8k_set_fan(val, speed); | ||
387 | break; | ||
388 | 395 | ||
389 | default: | 396 | switch (cmd) { |
390 | return -EINVAL; | 397 | case I8K_BIOS_VERSION: |
391 | } | 398 | if (copy_to_user(argp, &val, 4)) { |
392 | 399 | return -EFAULT; | |
393 | if (val < 0) { | 400 | } |
394 | return val; | 401 | break; |
395 | } | 402 | case I8K_MACHINE_ID: |
396 | 403 | if (copy_to_user(argp, buff, 16)) { | |
397 | switch (cmd) { | 404 | return -EFAULT; |
398 | case I8K_BIOS_VERSION: | 405 | } |
399 | if (copy_to_user(argp, &val, 4)) { | 406 | break; |
400 | return -EFAULT; | 407 | default: |
401 | } | 408 | if (copy_to_user(argp, &val, sizeof(int))) { |
402 | break; | 409 | return -EFAULT; |
403 | case I8K_MACHINE_ID: | 410 | } |
404 | if (copy_to_user(argp, buff, 16)) { | 411 | break; |
405 | return -EFAULT; | ||
406 | } | ||
407 | break; | ||
408 | default: | ||
409 | if (copy_to_user(argp, &val, sizeof(int))) { | ||
410 | return -EFAULT; | ||
411 | } | 412 | } |
412 | break; | ||
413 | } | ||
414 | 413 | ||
415 | return 0; | 414 | return 0; |
416 | } | 415 | } |
417 | 416 | ||
418 | /* | 417 | /* |
@@ -420,90 +419,87 @@ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | |||
420 | */ | 419 | */ |
421 | static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) | 420 | static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) |
422 | { | 421 | { |
423 | int n, fn_key, cpu_temp, ac_power; | 422 | int n, fn_key, cpu_temp, ac_power; |
424 | int left_fan, right_fan, left_speed, right_speed; | 423 | int left_fan, right_fan, left_speed, right_speed; |
425 | 424 | ||
426 | cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ | 425 | cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ |
427 | left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ | 426 | left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ |
428 | right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ | 427 | right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ |
429 | left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ | 428 | left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ |
430 | right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ | 429 | right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ |
431 | fn_key = i8k_get_fn_status(); /* 750 µs */ | 430 | fn_key = i8k_get_fn_status(); /* 750 µs */ |
432 | if (power_status) { | 431 | if (power_status) { |
433 | ac_power = i8k_get_power_status(); /* 14700 µs */ | 432 | ac_power = i8k_get_power_status(); /* 14700 µs */ |
434 | } else { | 433 | } else { |
435 | ac_power = -1; | 434 | ac_power = -1; |
436 | } | 435 | } |
437 | 436 | ||
438 | /* | 437 | /* |
439 | * Info: | 438 | * Info: |
440 | * | 439 | * |
441 | * 1) Format version (this will change if format changes) | 440 | * 1) Format version (this will change if format changes) |
442 | * 2) BIOS version | 441 | * 2) BIOS version |
443 | * 3) BIOS machine ID | 442 | * 3) BIOS machine ID |
444 | * 4) Cpu temperature | 443 | * 4) Cpu temperature |
445 | * 5) Left fan status | 444 | * 5) Left fan status |
446 | * 6) Right fan status | 445 | * 6) Right fan status |
447 | * 7) Left fan speed | 446 | * 7) Left fan speed |
448 | * 8) Right fan speed | 447 | * 8) Right fan speed |
449 | * 9) AC power | 448 | * 9) AC power |
450 | * 10) Fn Key status | 449 | * 10) Fn Key status |
451 | */ | 450 | */ |
452 | n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", | 451 | n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", |
453 | I8K_PROC_FMT, | 452 | I8K_PROC_FMT, |
454 | bios_version, | 453 | bios_version, |
455 | serial_number, | 454 | serial_number, |
456 | cpu_temp, | 455 | cpu_temp, |
457 | left_fan, | 456 | left_fan, |
458 | right_fan, | 457 | right_fan, left_speed, right_speed, ac_power, fn_key); |
459 | left_speed, | 458 | |
460 | right_speed, | 459 | return n; |
461 | ac_power, | ||
462 | fn_key); | ||
463 | |||
464 | return n; | ||
465 | } | 460 | } |
466 | 461 | ||
467 | static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos) | 462 | static ssize_t i8k_read(struct file *f, char __user * buffer, size_t len, |
463 | loff_t * fpos) | ||
468 | { | 464 | { |
469 | int n; | 465 | int n; |
470 | char info[128]; | 466 | char info[128]; |
471 | 467 | ||
472 | n = i8k_get_info(info, NULL, 0, 128); | 468 | n = i8k_get_info(info, NULL, 0, 128); |
473 | if (n <= 0) { | 469 | if (n <= 0) { |
474 | return n; | 470 | return n; |
475 | } | 471 | } |
476 | 472 | ||
477 | if (*fpos >= n) { | 473 | if (*fpos >= n) { |
478 | return 0; | 474 | return 0; |
479 | } | 475 | } |
480 | 476 | ||
481 | if ((*fpos + len) >= n) { | 477 | if ((*fpos + len) >= n) { |
482 | len = n - *fpos; | 478 | len = n - *fpos; |
483 | } | 479 | } |
484 | 480 | ||
485 | if (copy_to_user(buffer, info, len) != 0) { | 481 | if (copy_to_user(buffer, info, len) != 0) { |
486 | return -EFAULT; | 482 | return -EFAULT; |
487 | } | 483 | } |
488 | 484 | ||
489 | *fpos += len; | 485 | *fpos += len; |
490 | return len; | 486 | return len; |
491 | } | 487 | } |
492 | 488 | ||
493 | static char* __init string_trim(char *s, int size) | 489 | static char *__init string_trim(char *s, int size) |
494 | { | 490 | { |
495 | int len; | 491 | int len; |
496 | char *p; | 492 | char *p; |
497 | 493 | ||
498 | if ((len = strlen(s)) > size) { | 494 | if ((len = strlen(s)) > size) { |
499 | len = size; | 495 | len = size; |
500 | } | 496 | } |
501 | 497 | ||
502 | for (p=s+len-1; len && (*p==' '); len--,p--) { | 498 | for (p = s + len - 1; len && (*p == ' '); len--, p--) { |
503 | *p = '\0'; | 499 | *p = '\0'; |
504 | } | 500 | } |
505 | 501 | ||
506 | return s; | 502 | return s; |
507 | } | 503 | } |
508 | 504 | ||
509 | /* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ | 505 | /* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ |
@@ -515,111 +511,112 @@ static char* __init string_trim(char *s, int size) | |||
515 | * | | | 511 | * | | |
516 | * +-----------------------+ | 512 | * +-----------------------+ |
517 | */ | 513 | */ |
518 | static char* __init dmi_string(DMIHeader *dmi, u8 s) | 514 | static char *__init dmi_string(DMIHeader * dmi, u8 s) |
519 | { | 515 | { |
520 | u8 *p; | 516 | u8 *p; |
521 | |||
522 | if (!s) { | ||
523 | return ""; | ||
524 | } | ||
525 | s--; | ||
526 | 517 | ||
527 | p = (u8 *)dmi + dmi->length; | 518 | if (!s) { |
528 | while (s > 0) { | 519 | return ""; |
529 | p += strlen(p); | 520 | } |
530 | p++; | ||
531 | s--; | 521 | s--; |
532 | } | ||
533 | 522 | ||
534 | return p; | 523 | p = (u8 *) dmi + dmi->length; |
524 | while (s > 0) { | ||
525 | p += strlen(p); | ||
526 | p++; | ||
527 | s--; | ||
528 | } | ||
529 | |||
530 | return p; | ||
535 | } | 531 | } |
536 | 532 | ||
537 | static void __init dmi_decode(DMIHeader *dmi) | 533 | static void __init dmi_decode(DMIHeader * dmi) |
538 | { | 534 | { |
539 | u8 *data = (u8 *) dmi; | 535 | u8 *data = (u8 *) dmi; |
540 | char *p; | 536 | char *p; |
541 | 537 | ||
542 | #ifdef I8K_DEBUG | 538 | #ifdef I8K_DEBUG |
543 | int i; | 539 | int i; |
544 | printk("%08x ", (int)data); | 540 | printk("%08x ", (int)data); |
545 | for (i=0; i<data[1] && i<64; i++) { | 541 | for (i = 0; i < data[1] && i < 64; i++) { |
546 | printk("%02x ", data[i]); | 542 | printk("%02x ", data[i]); |
547 | } | 543 | } |
548 | printk("\n"); | 544 | printk("\n"); |
549 | #endif | 545 | #endif |
550 | 546 | ||
551 | switch (dmi->type) { | 547 | switch (dmi->type) { |
552 | case 0: /* BIOS Information */ | 548 | case 0: /* BIOS Information */ |
553 | p = dmi_string(dmi,data[5]); | 549 | p = dmi_string(dmi, data[5]); |
554 | if (*p) { | 550 | if (*p) { |
555 | strlcpy(bios_version, p, sizeof(bios_version)); | 551 | strlcpy(bios_version, p, sizeof(bios_version)); |
556 | string_trim(bios_version, sizeof(bios_version)); | 552 | string_trim(bios_version, sizeof(bios_version)); |
557 | } | 553 | } |
558 | break; | 554 | break; |
559 | case 1: /* System Information */ | 555 | case 1: /* System Information */ |
560 | p = dmi_string(dmi,data[4]); | 556 | p = dmi_string(dmi, data[4]); |
561 | if (*p) { | 557 | if (*p) { |
562 | strlcpy(system_vendor, p, sizeof(system_vendor)); | 558 | strlcpy(system_vendor, p, sizeof(system_vendor)); |
563 | string_trim(system_vendor, sizeof(system_vendor)); | 559 | string_trim(system_vendor, sizeof(system_vendor)); |
564 | } | 560 | } |
565 | p = dmi_string(dmi,data[5]); | 561 | p = dmi_string(dmi, data[5]); |
566 | if (*p) { | 562 | if (*p) { |
567 | strlcpy(product_name, p, sizeof(product_name)); | 563 | strlcpy(product_name, p, sizeof(product_name)); |
568 | string_trim(product_name, sizeof(product_name)); | 564 | string_trim(product_name, sizeof(product_name)); |
569 | } | 565 | } |
570 | p = dmi_string(dmi,data[7]); | 566 | p = dmi_string(dmi, data[7]); |
571 | if (*p) { | 567 | if (*p) { |
572 | strlcpy(serial_number, p, sizeof(serial_number)); | 568 | strlcpy(serial_number, p, sizeof(serial_number)); |
573 | string_trim(serial_number, sizeof(serial_number)); | 569 | string_trim(serial_number, sizeof(serial_number)); |
574 | } | 570 | } |
575 | break; | 571 | break; |
576 | } | 572 | } |
577 | } | 573 | } |
578 | 574 | ||
579 | static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) | 575 | static int __init dmi_table(u32 base, int len, int num, |
576 | void (*fn) (DMIHeader *)) | ||
580 | { | 577 | { |
581 | u8 *buf; | 578 | u8 *buf; |
582 | u8 *data; | 579 | u8 *data; |
583 | DMIHeader *dmi; | 580 | DMIHeader *dmi; |
584 | int i = 1; | 581 | int i = 1; |
585 | 582 | ||
586 | buf = ioremap(base, len); | 583 | buf = ioremap(base, len); |
587 | if (buf == NULL) { | 584 | if (buf == NULL) { |
588 | return -1; | 585 | 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 | } | 586 | } |
605 | fn(dmi); | 587 | data = buf; |
606 | data += dmi->length; | 588 | |
607 | /* | 589 | /* |
608 | * Don't go off the end of the data if there is | 590 | * Stop when we see al the items the table claimed to have |
609 | * stuff looking like string fill past the end | 591 | * or we run off the end of the table (also happens) |
610 | */ | 592 | */ |
611 | while (((data-buf) < len) && (*data || data[1])) { | 593 | while ((i < num) && ((data - buf) < len)) { |
612 | data++; | 594 | dmi = (DMIHeader *) data; |
595 | /* | ||
596 | * Avoid misparsing crud if the length of the last | ||
597 | * record is crap | ||
598 | */ | ||
599 | if ((data - buf + dmi->length) >= len) { | ||
600 | break; | ||
601 | } | ||
602 | fn(dmi); | ||
603 | data += dmi->length; | ||
604 | /* | ||
605 | * Don't go off the end of the data if there is | ||
606 | * stuff looking like string fill past the end | ||
607 | */ | ||
608 | while (((data - buf) < len) && (*data || data[1])) { | ||
609 | data++; | ||
610 | } | ||
611 | data += 2; | ||
612 | i++; | ||
613 | } | 613 | } |
614 | data += 2; | 614 | iounmap(buf); |
615 | i++; | ||
616 | } | ||
617 | iounmap(buf); | ||
618 | 615 | ||
619 | return 0; | 616 | return 0; |
620 | } | 617 | } |
621 | 618 | ||
622 | static int __init dmi_iterate(void (*decode)(DMIHeader *)) | 619 | static int __init dmi_iterate(void (*decode) (DMIHeader *)) |
623 | { | 620 | { |
624 | unsigned char buf[20]; | 621 | unsigned char buf[20]; |
625 | void __iomem *p = ioremap(0xe0000, 0x20000), *q; | 622 | void __iomem *p = ioremap(0xe0000, 0x20000), *q; |
@@ -629,20 +626,20 @@ static int __init dmi_iterate(void (*decode)(DMIHeader *)) | |||
629 | 626 | ||
630 | for (q = p; q < p + 0x20000; q += 16) { | 627 | for (q = p; q < p + 0x20000; q += 16) { |
631 | memcpy_fromio(buf, q, 20); | 628 | memcpy_fromio(buf, q, 20); |
632 | if (memcmp(buf, "_DMI_", 5)==0) { | 629 | if (memcmp(buf, "_DMI_", 5) == 0) { |
633 | u16 num = buf[13]<<8 | buf[12]; | 630 | u16 num = buf[13] << 8 | buf[12]; |
634 | u16 len = buf [7]<<8 | buf [6]; | 631 | u16 len = buf[7] << 8 | buf[6]; |
635 | u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; | 632 | u32 base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8]; |
636 | #ifdef I8K_DEBUG | 633 | #ifdef I8K_DEBUG |
637 | printk(KERN_INFO "DMI %d.%d present.\n", | 634 | printk(KERN_INFO "DMI %d.%d present.\n", |
638 | buf[14]>>4, buf[14]&0x0F); | 635 | buf[14] >> 4, buf[14] & 0x0F); |
639 | printk(KERN_INFO "%d structures occupying %d bytes.\n", | 636 | printk(KERN_INFO "%d structures occupying %d bytes.\n", |
640 | buf[13]<<8 | buf[12], | 637 | buf[13] << 8 | buf[12], buf[7] << 8 | buf[6]); |
641 | buf [7]<<8 | buf[6]); | ||
642 | printk(KERN_INFO "DMI table at 0x%08X.\n", | 638 | printk(KERN_INFO "DMI table at 0x%08X.\n", |
643 | buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]); | 639 | buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | |
640 | buf[8]); | ||
644 | #endif | 641 | #endif |
645 | if (dmi_table(base, len, num, decode)==0) { | 642 | if (dmi_table(base, len, num, decode) == 0) { |
646 | iounmap(p); | 643 | iounmap(p); |
647 | return 0; | 644 | return 0; |
648 | } | 645 | } |
@@ -651,6 +648,7 @@ static int __init dmi_iterate(void (*decode)(DMIHeader *)) | |||
651 | iounmap(p); | 648 | iounmap(p); |
652 | return -1; | 649 | return -1; |
653 | } | 650 | } |
651 | |||
654 | /* end of DMI code */ | 652 | /* end of DMI code */ |
655 | 653 | ||
656 | /* | 654 | /* |
@@ -658,29 +656,30 @@ static int __init dmi_iterate(void (*decode)(DMIHeader *)) | |||
658 | */ | 656 | */ |
659 | static int __init i8k_dmi_probe(void) | 657 | static int __init i8k_dmi_probe(void) |
660 | { | 658 | { |
661 | char **p; | 659 | char **p; |
662 | 660 | ||
663 | if (dmi_iterate(dmi_decode) != 0) { | 661 | if (dmi_iterate(dmi_decode) != 0) { |
664 | printk(KERN_INFO "i8k: unable to get DMI information\n"); | 662 | printk(KERN_INFO "i8k: unable to get DMI information\n"); |
665 | return -ENODEV; | 663 | return -ENODEV; |
666 | } | 664 | } |
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 | 665 | ||
673 | for (p=supported_models; ; p++) { | 666 | if (strncmp(system_vendor, DELL_SIGNATURE, strlen(DELL_SIGNATURE)) != 0) { |
674 | if (!*p) { | 667 | printk(KERN_INFO "i8k: not running on a Dell system\n"); |
675 | printk(KERN_INFO "i8k: unsupported model: %s\n", product_name); | 668 | return -ENODEV; |
676 | return -ENODEV; | ||
677 | } | 669 | } |
678 | if (strncmp(product_name,*p,strlen(*p)) == 0) { | 670 | |
679 | break; | 671 | for (p = supported_models;; p++) { |
672 | if (!*p) { | ||
673 | printk(KERN_INFO "i8k: unsupported model: %s\n", | ||
674 | product_name); | ||
675 | return -ENODEV; | ||
676 | } | ||
677 | if (strncmp(product_name, *p, strlen(*p)) == 0) { | ||
678 | break; | ||
679 | } | ||
680 | } | 680 | } |
681 | } | ||
682 | 681 | ||
683 | return 0; | 682 | return 0; |
684 | } | 683 | } |
685 | 684 | ||
686 | /* | 685 | /* |
@@ -688,59 +687,60 @@ static int __init i8k_dmi_probe(void) | |||
688 | */ | 687 | */ |
689 | static int __init i8k_probe(void) | 688 | static int __init i8k_probe(void) |
690 | { | 689 | { |
691 | char buff[4]; | 690 | char buff[4]; |
692 | int version; | 691 | int version; |
693 | int smm_found = 0; | 692 | int smm_found = 0; |
694 | 693 | ||
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 | /* | 694 | /* |
725 | * If DMI BIOS version is unknown use SMM BIOS version. | 695 | * Get DMI information |
726 | */ | 696 | */ |
727 | if (bios_version[0] == '?') { | 697 | if (i8k_dmi_probe() != 0) { |
728 | strcpy(bios_version, buff); | 698 | printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", |
699 | system_vendor, product_name, bios_version); | ||
729 | } | 700 | } |
701 | |||
730 | /* | 702 | /* |
731 | * Check if the two versions match. | 703 | * Get SMM Dell signature |
732 | */ | 704 | */ |
733 | if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) { | 705 | if (i8k_get_dell_signature() != 0) { |
734 | printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n", | 706 | printk(KERN_INFO "i8k: unable to get SMM Dell signature\n"); |
735 | buff, bios_version); | 707 | } else { |
708 | smm_found = 1; | ||
736 | } | 709 | } |
737 | } | ||
738 | 710 | ||
739 | if (!smm_found && !force) { | 711 | /* |
740 | return -ENODEV; | 712 | * Get SMM BIOS version. |
741 | } | 713 | */ |
714 | version = i8k_get_bios_version(); | ||
715 | if (version <= 0) { | ||
716 | printk(KERN_INFO "i8k: unable to get SMM BIOS version\n"); | ||
717 | } else { | ||
718 | smm_found = 1; | ||
719 | buff[0] = (version >> 16) & 0xff; | ||
720 | buff[1] = (version >> 8) & 0xff; | ||
721 | buff[2] = (version) & 0xff; | ||
722 | buff[3] = '\0'; | ||
723 | /* | ||
724 | * If DMI BIOS version is unknown use SMM BIOS version. | ||
725 | */ | ||
726 | if (bios_version[0] == '?') { | ||
727 | strcpy(bios_version, buff); | ||
728 | } | ||
729 | /* | ||
730 | * Check if the two versions match. | ||
731 | */ | ||
732 | if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) { | ||
733 | printk(KERN_INFO | ||
734 | "i8k: BIOS version mismatch: %s != %s\n", buff, | ||
735 | bios_version); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | if (!smm_found && !force) { | ||
740 | return -ENODEV; | ||
741 | } | ||
742 | 742 | ||
743 | return 0; | 743 | return 0; |
744 | } | 744 | } |
745 | 745 | ||
746 | #ifdef MODULE | 746 | #ifdef MODULE |
@@ -748,40 +748,40 @@ static | |||
748 | #endif | 748 | #endif |
749 | int __init i8k_init(void) | 749 | int __init i8k_init(void) |
750 | { | 750 | { |
751 | struct proc_dir_entry *proc_i8k; | 751 | struct proc_dir_entry *proc_i8k; |
752 | 752 | ||
753 | /* Are we running on an supported laptop? */ | 753 | /* Are we running on an supported laptop? */ |
754 | if (i8k_probe() != 0) { | 754 | if (i8k_probe() != 0) { |
755 | return -ENODEV; | 755 | return -ENODEV; |
756 | } | 756 | } |
757 | 757 | ||
758 | /* Register the proc entry */ | 758 | /* Register the proc entry */ |
759 | proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info); | 759 | proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info); |
760 | if (!proc_i8k) { | 760 | if (!proc_i8k) { |
761 | return -ENOENT; | 761 | return -ENOENT; |
762 | } | 762 | } |
763 | proc_i8k->proc_fops = &i8k_fops; | 763 | proc_i8k->proc_fops = &i8k_fops; |
764 | proc_i8k->owner = THIS_MODULE; | 764 | proc_i8k->owner = THIS_MODULE; |
765 | 765 | ||
766 | printk(KERN_INFO | 766 | printk(KERN_INFO |
767 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", | 767 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", |
768 | I8K_VERSION); | 768 | I8K_VERSION); |
769 | 769 | ||
770 | return 0; | 770 | return 0; |
771 | } | 771 | } |
772 | 772 | ||
773 | #ifdef MODULE | 773 | #ifdef MODULE |
774 | int init_module(void) | 774 | int init_module(void) |
775 | { | 775 | { |
776 | return i8k_init(); | 776 | return i8k_init(); |
777 | } | 777 | } |
778 | 778 | ||
779 | void cleanup_module(void) | 779 | void cleanup_module(void) |
780 | { | 780 | { |
781 | /* Remove the proc entry */ | 781 | /* Remove the proc entry */ |
782 | remove_proc_entry("i8k", NULL); | 782 | remove_proc_entry("i8k", NULL); |
783 | 783 | ||
784 | printk(KERN_INFO "i8k: module unloaded\n"); | 784 | printk(KERN_INFO "i8k: module unloaded\n"); |
785 | } | 785 | } |
786 | #endif | 786 | #endif |
787 | 787 | ||