File: /usr/src/linux/drivers/acpi/ospm/system/sm_osl.c
1 /******************************************************************************
2 *
3 * Module Name: sm_osl.c
4 * $Revision: 16 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 Andrew Grover
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/types.h>
31 #include <linux/proc_fs.h>
32 #include <linux/pm.h>
33 #include <asm/uaccess.h>
34 #include <linux/acpi.h>
35 #include <asm/io.h>
36 #include <linux/mc146818rtc.h>
37 #include <linux/delay.h>
38
39 #include <acpi.h>
40 #include "sm.h"
41
42
43 MODULE_AUTHOR("Andrew Grover");
44 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver");
45 MODULE_LICENSE("GPL");
46
47
48 #define SM_PROC_INFO "info"
49 #define SM_PROC_DSDT "dsdt"
50
51 extern struct proc_dir_entry *bm_proc_root;
52 struct proc_dir_entry *sm_proc_root = NULL;
53 static void (*sm_pm_power_off)(void) = NULL;
54
55 static ssize_t sm_osl_read_dsdt(struct file *, char *, size_t, loff_t *);
56
57 static struct file_operations proc_dsdt_operations = {
58 read: sm_osl_read_dsdt,
59 };
60
61 static acpi_status sm_osl_suspend(u32 state);
62
63 struct proc_dir_entry *bm_proc_sleep;
64 struct proc_dir_entry *bm_proc_alarm;
65 struct proc_dir_entry *bm_proc_gpe;
66
67 static int
68 sm_osl_proc_read_sleep (
69 char *page,
70 char **start,
71 off_t off,
72 int count,
73 int *eof,
74 void *context)
75 {
76 SM_CONTEXT *system = (SM_CONTEXT*) context;
77 char *str = page;
78 int len;
79 int i;
80
81 if (!system)
82 goto end;
83
84 if (off != 0)
85 goto end;
86
87 for (i = 0; i <= ACPI_S5; i++) {
88 if (system->states[i])
89 str += sprintf(str,"S%d ", i);
90 }
91
92 str += sprintf(str, "\n");
93
94 end:
95
96 len = (str - page);
97 if (len < (off + count))
98 *eof = 1;
99
100 *start = page + off;
101 len -= off;
102
103 if (len > count)
104 len = count;
105
106 if (len < 0)
107 len = 0;
108
109 return (len);
110 }
111
112 int sm_osl_proc_write_sleep (struct file *file,
113 const char *buffer,
114 unsigned long count,
115 void *data)
116 {
117 SM_CONTEXT *system = (SM_CONTEXT*) data;
118 char str[10];
119 char *strend;
120 unsigned long value;
121
122 if (count > (sizeof(str) - 1))
123 return -EINVAL;
124
125 if (copy_from_user(str,buffer,count))
126 return -EFAULT;
127
128 str[count] = '\0';
129
130 value = simple_strtoul(str,&strend,0);
131 if (str == strend)
132 return -EINVAL;
133
134 if (value == 0 || value >= ACPI_S5)
135 return -EINVAL;
136
137 /*
138 * make sure that the sleep state is supported
139 */
140 if (system->states[value] != TRUE)
141 return -EINVAL;
142
143 sm_osl_suspend(value);
144
145 return (count);
146 }
147
148
149 /****************************************************************************
150 *
151 * FUNCTION: sm_osl_proc_read_info
152 *
153 ****************************************************************************/
154
155 static int
156 sm_osl_proc_read_info (
157 char *page,
158 char **start,
159 off_t off,
160 int count,
161 int *eof,
162 void *context)
163 {
164 acpi_status status = AE_OK;
165 SM_CONTEXT *system = NULL;
166 char *p = page;
167 int len;
168 acpi_system_info system_info;
169 acpi_buffer buffer;
170 u32 i = 0;
171
172 if (!context) {
173 goto end;
174 }
175
176 system = (SM_CONTEXT*) context;
177
178 /* don't get status more than once for a single proc read */
179 if (off != 0) {
180 goto end;
181 }
182
183 /*
184 * Get ACPI CA Information.
185 */
186 buffer.length = sizeof(system_info);
187 buffer.pointer = &system_info;
188
189 status = acpi_get_system_info(&buffer);
190 if (ACPI_FAILURE(status)) {
191 p += sprintf(p, "ACPI-CA Version: unknown\n");
192 }
193 else {
194 p += sprintf(p, "ACPI-CA Version: %x\n",
195 system_info.acpi_ca_version);
196 }
197
198 p += sprintf(p, "Sx States Supported: ");
199 for (i=0; i<SM_MAX_SYSTEM_STATES; i++) {
200 if (system->states[i]) {
201 p += sprintf(p, "S%d ", i);
202 }
203 }
204 p += sprintf(p, "\n");
205
206 end:
207 len = (p - page);
208 if (len <= off+count) *eof = 1;
209 *start = page + off;
210 len -= off;
211 if (len>count) len = count;
212 if (len<0) len = 0;
213
214 return(len);
215 }
216
217 /****************************************************************************
218 *
219 * FUNCTION: sm_osl_read_dsdt
220 *
221 ****************************************************************************/
222
223 static ssize_t
224 sm_osl_read_dsdt(
225 struct file *file,
226 char *buf,
227 size_t count,
228 loff_t *ppos)
229 {
230 acpi_buffer acpi_buf;
231 void *data;
232 size_t size = 0;
233
234 acpi_buf.length = 0;
235 acpi_buf.pointer = NULL;
236
237
238 /* determine what buffer size we will need */
239 if (acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf) != AE_BUFFER_OVERFLOW) {
240 return 0;
241 }
242
243 acpi_buf.pointer = kmalloc(acpi_buf.length, GFP_KERNEL);
244 if (!acpi_buf.pointer) {
245 return -ENOMEM;
246 }
247
248 /* get the table for real */
249 if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf))) {
250 kfree(acpi_buf.pointer);
251 return 0;
252 }
253
254 if (*ppos < acpi_buf.length) {
255 data = acpi_buf.pointer + file->f_pos;
256 size = acpi_buf.length - file->f_pos;
257 if (size > count)
258 size = count;
259 if (copy_to_user(buf, data, size)) {
260 kfree(acpi_buf.pointer);
261 return -EFAULT;
262 }
263 }
264
265 kfree(acpi_buf.pointer);
266
267 *ppos += size;
268
269 return size;
270 }
271
272 static int
273 sm_osl_proc_read_alarm (
274 char *page,
275 char **start,
276 off_t off,
277 int count,
278 int *eof,
279 void *context)
280 {
281 char *str = page;
282 int len;
283 u32 sec,min,hr;
284 u32 day,mo,yr;
285
286 if (off != 0) goto out;
287
288 spin_lock(&rtc_lock);
289 sec = CMOS_READ(RTC_SECONDS_ALARM);
290 min = CMOS_READ(RTC_MINUTES_ALARM);
291 hr = CMOS_READ(RTC_HOURS_ALARM);
292
293 #if 0
294 /* if I ever get an FACP with proper values, maybe I'll enable this code */
295 if (acpi_gbl_FADT->day_alrm)
296 day = CMOS_READ(acpi_gbl_FADT->day_alrm);
297 else
298 day = CMOS_READ(RTC_DAY_OF_MONTH);
299 if (acpi_gbl_FADT->mon_alrm)
300 mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
301 else
302 mo = CMOS_READ(RTC_MONTH);;
303 if (acpi_gbl_FADT->century)
304 yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
305 else
306 yr = CMOS_READ(RTC_YEAR);
307 #else
308 day = CMOS_READ(RTC_DAY_OF_MONTH);
309 mo = CMOS_READ(RTC_MONTH);
310 yr = CMOS_READ(RTC_YEAR);
311 #endif
312 spin_unlock(&rtc_lock);
313
314 BCD_TO_BIN(sec);
315 BCD_TO_BIN(min);
316 BCD_TO_BIN(hr);
317 BCD_TO_BIN(day);
318 BCD_TO_BIN(mo);
319 BCD_TO_BIN(yr);
320
321 str += sprintf(str,"%4.4u-",yr);
322
323 str += (mo > 12) ?
324 sprintf(str,"**-") :
325 sprintf(str,"%2.2u-",mo);
326
327 str += (day > 31) ?
328 sprintf(str,"** ") :
329 sprintf(str,"%2.2u ",day);
330
331 str += (hr > 23) ?
332 sprintf(str,"**:") :
333 sprintf(str,"%2.2u:",hr);
334
335 str += (min > 59) ?
336 sprintf(str,"**:") :
337 sprintf(str,"%2.2u:",min);
338
339 str += (sec > 59) ?
340 sprintf(str,"**\n") :
341 sprintf(str,"%2.2u\n",sec);
342
343 out:
344 len = str - page;
345
346 if (len < count) *eof = 1;
347 else if (len > count) len = count;
348
349 if (len < 0) len = 0;
350
351 *start = page;
352
353 return len;
354 }
355
356 static int get_date_field(char **str, u32 *value)
357 {
358 char *next,*strend;
359 int error = -EINVAL;
360
361 /* try to find delimeter, only to insert null;
362 * the end of string won't have one, but is still valid
363 */
364 next = strpbrk(*str,"- :");
365 if (next) *next++ = '\0';
366
367 *value = simple_strtoul(*str,&strend,10);
368
369 /* signal success if we got a good digit */
370 if (strend != *str) error = 0;
371
372 if (next) *str = next;
373 return error;
374 }
375
376
377
378 int sm_osl_proc_write_alarm (
379 struct file *file,
380 const char *buffer,
381 unsigned long count,
382 void *data)
383 {
384 char buf[30];
385 char *str = buf;
386 u32 sec,min,hr;
387 u32 day,mo,yr;
388 int adjust = 0;
389 unsigned char rtc_control;
390 int error = -EINVAL;
391
392 if (count > sizeof(buf) - 1) return -EINVAL;
393
394 if (copy_from_user(str,buffer,count)) return -EFAULT;
395
396 str[count] = '\0';
397 /* check for time adjustment */
398 if (str[0] == '+') {
399 str++;
400 adjust = 1;
401 }
402
403 if ((error = get_date_field(&str,&yr))) goto out;
404 if ((error = get_date_field(&str,&mo))) goto out;
405 if ((error = get_date_field(&str,&day))) goto out;
406 if ((error = get_date_field(&str,&hr))) goto out;
407 if ((error = get_date_field(&str,&min))) goto out;
408 if ((error = get_date_field(&str,&sec))) goto out;
409
410
411 if (sec > 59) {
412 min += 1;
413 sec -= 60;
414 }
415 if (min > 59) {
416 hr += 1;
417 min -= 60;
418 }
419 if (hr > 23) {
420 day += 1;
421 hr -= 24;
422 }
423 if (day > 31) {
424 mo += 1;
425 day -= 31;
426 }
427 if (mo > 12) {
428 yr += 1;
429 mo -= 12;
430 }
431
432 spin_lock_irq(&rtc_lock);
433 rtc_control = CMOS_READ(RTC_CONTROL);
434 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
435 BIN_TO_BCD(yr);
436 BIN_TO_BCD(mo);
437 BIN_TO_BCD(day);
438 BIN_TO_BCD(hr);
439 BIN_TO_BCD(min);
440 BIN_TO_BCD(sec);
441 }
442
443 if (adjust) {
444 yr += CMOS_READ(RTC_YEAR);
445 mo += CMOS_READ(RTC_MONTH);
446 day += CMOS_READ(RTC_DAY_OF_MONTH);
447 hr += CMOS_READ(RTC_HOURS);
448 min += CMOS_READ(RTC_MINUTES);
449 sec += CMOS_READ(RTC_SECONDS);
450 }
451 spin_unlock_irq(&rtc_lock);
452
453 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
454 BCD_TO_BIN(yr);
455 BCD_TO_BIN(mo);
456 BCD_TO_BIN(day);
457 BCD_TO_BIN(hr);
458 BCD_TO_BIN(min);
459 BCD_TO_BIN(sec);
460 }
461
462 if (sec > 59) {
463 min++;
464 sec -= 60;
465 }
466 if (min > 59) {
467 hr++;
468 min -= 60;
469 }
470 if (hr > 23) {
471 day++;
472 hr -= 24;
473 }
474 if (day > 31) {
475 mo++;
476 day -= 31;
477 }
478 if (mo > 12) {
479 yr++;
480 mo -= 12;
481 }
482 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
483 BIN_TO_BCD(yr);
484 BIN_TO_BCD(mo);
485 BIN_TO_BCD(day);
486 BIN_TO_BCD(hr);
487 BIN_TO_BCD(min);
488 BIN_TO_BCD(sec);
489 }
490
491 spin_lock_irq(&rtc_lock);
492 /* write the fields the rtc knows about */
493 CMOS_WRITE(hr,RTC_HOURS_ALARM);
494 CMOS_WRITE(min,RTC_MINUTES_ALARM);
495 CMOS_WRITE(sec,RTC_SECONDS_ALARM);
496
497 /* If the system supports an enhanced alarm, it will have non-zero
498 * offsets into the CMOS RAM here.
499 * Which for some reason are pointing to the RTC area of memory.
500 */
501 #if 0
502 if (acpi_gbl_FADT->day_alrm) CMOS_WRITE(day,acpi_gbl_FADT->day_alrm);
503 if (acpi_gbl_FADT->mon_alrm) CMOS_WRITE(mo,acpi_gbl_FADT->mon_alrm);
504 if (acpi_gbl_FADT->century) CMOS_WRITE(yr / 100,acpi_gbl_FADT->century);
505 #endif
506 /* enable the rtc alarm interrupt */
507 if (!(rtc_control & RTC_AIE)) {
508 rtc_control |= RTC_AIE;
509 CMOS_WRITE(rtc_control,RTC_CONTROL);
510 CMOS_READ(RTC_INTR_FLAGS);
511 }
512
513 /* unlock the lock on the rtc now that we're done with it */
514 spin_unlock_irq(&rtc_lock);
515
516 acpi_hw_register_bit_access(ACPI_WRITE,ACPI_MTX_LOCK, RTC_EN, 1);
517
518 file->f_pos += count;
519
520 error = 0;
521 out:
522 return error ? error : count;
523 }
524
525 static int
526 sm_osl_proc_read_gpe(
527 char *page,
528 char **start,
529 off_t off,
530 int count,
531 int *eof,
532 void *context)
533 {
534 char *str = page;
535 int size;
536 int length;
537 int i;
538 u32 addr,data;
539
540 if (off) goto out;
541
542 if (acpi_gbl_FADT->V1_gpe0blk) {
543 length = acpi_gbl_FADT->gpe0blk_len / 2;
544
545 str += sprintf(str,"GPE0: ");
546
547 for (i = length; i > 0; i--) {
548 addr = GPE0_EN_BLOCK | (i - 1);
549 data = acpi_hw_register_read(ACPI_MTX_LOCK,addr);
550 str += sprintf(str,"%2.2x ",data);
551 }
552 str += sprintf(str,"\n");
553
554 str += sprintf(str,"Status: ");
555 for (i = length; i > 0; i--) {
556 addr = GPE0_STS_BLOCK | (i - 1);
557 data = acpi_hw_register_read(ACPI_MTX_LOCK,addr);
558 str += sprintf(str,"%2.2x ",data);
559 }
560 str += sprintf(str,"\n");
561 }
562
563 if (acpi_gbl_FADT->V1_gpe1_blk) {
564 length = acpi_gbl_FADT->gpe1_blk_len / 2;
565
566
567 str += sprintf(str,"GPE1: ");
568 for (i = length; i > 0; i--) {
569 addr = GPE1_EN_BLOCK | (i - 1);
570 data = acpi_hw_register_read(ACPI_MTX_LOCK,addr);
571 str += sprintf(str,"%2.2x",data);
572 }
573 str += sprintf(str,"\n");
574
575 str += sprintf(str,"Status: ");
576 for (i = length; i > 0; i--) {
577 addr = GPE1_STS_BLOCK | (i - 1);
578 data = acpi_hw_register_read(ACPI_MTX_LOCK,addr);
579 str += sprintf(str,"%2.2x",data);
580 }
581 str += sprintf(str,"\n");
582 }
583 out:
584 size = str - page;
585 if (size < count) *eof = 1;
586 else if (size > count) size = count;
587
588 if (size < 0) size = 0;
589 *start = page;
590
591 return size;
592 }
593
594 static int
595 sm_osl_proc_write_gpe (
596 struct file *file,
597 const char *buffer,
598 unsigned long count,
599 void *data)
600 {
601 char buf[256];
602 char *str = buf;
603 char *next;
604 int error = -EINVAL;
605 u32 addr,value = 0;
606
607 if (count > sizeof(buf) + 1) return -EINVAL;
608
609 if (copy_from_user(str,buffer,count)) return -EFAULT;
610
611 str[count] = '\0';
612
613 /* set addr to which block to refer to */
614 if (!strncmp(str,"GPE0 ",5)) addr = GPE0_EN_BLOCK;
615 else if (!strncmp(str,"GPE1 ",5)) addr = GPE1_EN_BLOCK;
616 else goto out;
617
618 str += 5;
619
620 /* set low order bits to index of bit to set */
621 addr |= simple_strtoul(str,&next,0);
622 if (next == str) goto out;
623
624 if (next) {
625 str = ++next;
626 value = simple_strtoul(str,&next,0);
627 if (next == str) value = 1;
628 }
629
630 value = acpi_hw_register_bit_access(ACPI_WRITE,ACPI_MTX_LOCK,addr,(value ? 1 : 0));
631
632 error = 0;
633 out:
634 return error ? error : count;
635 }
636
637
638 /****************************************************************************
639 *
640 * FUNCTION: sm_osl_suspend
641 *
642 * PARAMETERS: %state: Sleep state to enter. Assumed that caller has filtered
643 * out bogus values, so it's one of S1, S2, S3 or S4
644 *
645 * RETURN: ACPI_STATUS, whether or not we successfully entered and
646 * exited sleep.
647 *
648 * DESCRIPTION:
649 * This function is the meat of the sleep routine, as far as the ACPI-CA is
650 * concerned.
651 *
652 * See Chapter 9 of the ACPI 2.0 spec for details concerning the methodology here.
653 *
654 * It will do the following things:
655 * - Call arch-specific routines to save the processor and kernel state
656 * - Call acpi_enter_sleep_state to actually go to sleep
657 * ....
658 * When we wake back up, we will:
659 * - Restore the processor and kernel state
660 * - Return to the user
661 *
662 * By having this routine in here, it hides it from every part of the CA,
663 * so it can remain OS-independent. The only function that calls this is
664 * sm_proc_write_sleep, which gets the sleep state to enter from the user.
665 *
666 ****************************************************************************/
667 static acpi_status
668 sm_osl_suspend(u32 state)
669 {
670 acpi_status status = AE_ERROR;
671 unsigned long wakeup_address;
672
673 /* get out if state is invalid */
674 if (state < ACPI_S1 || state > ACPI_S5)
675 goto acpi_sleep_done;
676
677 /* make sure we don't get any suprises */
678 disable();
679
680 /* TODO: save device state and suspend them */
681
682 /* save the processor state to memory if going into S2 or S3;
683 * save it to disk if going into S4.
684 * Also, set the FWV if going into an STR state
685 */
686 if (state == ACPI_S2 || state == ACPI_S3) {
687 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
688 wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done);
689
690 if (!wakeup_address) goto acpi_sleep_done;
691
692 acpi_set_firmware_waking_vector(
693 (ACPI_PHYSICAL_ADDRESS)wakeup_address);
694 #endif
695 } else if (state == ACPI_S4)
696 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
697 if (acpi_save_state_disk((unsigned long)&&acpi_sleep_done))
698 goto acpi_sleep_done;
699 #endif
700
701 /* set status, since acpi_enter_sleep_state won't return unless something
702 * goes wrong, or it's just S1.
703 */
704 status = AE_OK;
705
706 mdelay(10);
707 status = acpi_enter_sleep_state(state);
708
709 acpi_sleep_done:
710
711 /* pause for a bit to allow devices to come back on */
712 mdelay(10);
713
714 /* make sure that the firmware waking vector is reset */
715 acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS)0);
716
717 acpi_leave_sleep_state(state);
718
719 /* TODO: resume devices and restore their state */
720
721 enable();
722 return status;
723 }
724
725
726 /****************************************************************************
727 *
728 * FUNCTION: sm_osl_power_down
729 *
730 ****************************************************************************/
731
732 void
733 sm_osl_power_down (void)
734 {
735 /* Power down the system (S5 = soft off). */
736 sm_osl_suspend(ACPI_S5);
737 }
738
739
740 /****************************************************************************
741 *
742 * FUNCTION: sm_osl_add_device
743 *
744 ****************************************************************************/
745
746 acpi_status
747 sm_osl_add_device(
748 SM_CONTEXT *system)
749 {
750 u32 i = 0;
751 struct proc_dir_entry *bm_proc_dsdt;
752
753 if (!system) {
754 return(AE_BAD_PARAMETER);
755 }
756
757 printk("ACPI: System firmware supports");
758 for (i=0; i<SM_MAX_SYSTEM_STATES; i++) {
759 if (system->states[i]) {
760 printk(" S%d", i);
761 }
762 }
763 printk("\n");
764
765 if (system->states[ACPI_STATE_S5]) {
766 sm_pm_power_off = pm_power_off;
767 pm_power_off = sm_osl_power_down;
768 }
769
770 create_proc_read_entry(SM_PROC_INFO, S_IRUGO,
771 sm_proc_root, sm_osl_proc_read_info, (void*)system);
772
773 bm_proc_sleep = create_proc_read_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
774 sm_proc_root, sm_osl_proc_read_sleep, (void*)system);
775 if (bm_proc_sleep)
776 bm_proc_sleep->write_proc = sm_osl_proc_write_sleep;
777
778 bm_proc_alarm = create_proc_read_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
779 sm_proc_root,sm_osl_proc_read_alarm, NULL);
780 if (bm_proc_alarm)
781 bm_proc_alarm->write_proc = sm_osl_proc_write_alarm;
782
783 bm_proc_gpe = create_proc_read_entry("gpe", S_IFREG | S_IRUGO | S_IWUSR,
784 sm_proc_root,sm_osl_proc_read_gpe,NULL);
785 if (bm_proc_gpe)
786 bm_proc_gpe->write_proc = sm_osl_proc_write_gpe;
787
788 /*
789 * Get a wakeup address for use when we come back from sleep.
790 * At least on IA-32, this needs to be in low memory.
791 * When sleep is supported on other arch's, then we may want
792 * to move this out to another place, but GFP_LOW should suffice
793 * for now.
794 */
795 #if 0
796 if (system->states[ACPI_S3] || system->states[ACPI_S4]) {
797 acpi_wakeup_address = (unsigned long)virt_to_phys(get_free_page(GFP_LOWMEM));
798 printk(KERN_INFO "ACPI: Have wakeup address 0x%8.8x\n",acpi_wakeup_address);
799 }
800 #endif
801
802 /*
803 * This returns more than a page, so we need to use our own file ops,
804 * not proc's generic ones
805 */
806 bm_proc_dsdt = create_proc_entry(SM_PROC_DSDT, S_IRUSR, sm_proc_root);
807 if (bm_proc_dsdt) {
808 bm_proc_dsdt->proc_fops = &proc_dsdt_operations;
809 }
810
811 return(AE_OK);
812 }
813
814
815 /****************************************************************************
816 *
817 * FUNCTION: sm_osl_remove_device
818 *
819 ****************************************************************************/
820
821 acpi_status
822 sm_osl_remove_device (
823 SM_CONTEXT *system)
824 {
825 if (!system) {
826 return(AE_BAD_PARAMETER);
827 }
828
829 remove_proc_entry(SM_PROC_INFO, sm_proc_root);
830 remove_proc_entry(SM_PROC_DSDT, sm_proc_root);
831
832 return(AE_OK);
833 }
834
835
836 /****************************************************************************
837 *
838 * FUNCTION: sm_osl_generate_event
839 *
840 ****************************************************************************/
841
842 acpi_status
843 sm_osl_generate_event (
844 u32 event,
845 SM_CONTEXT *system)
846 {
847 acpi_status status = AE_OK;
848
849 if (!system) {
850 return(AE_BAD_PARAMETER);
851 }
852
853 switch (event) {
854
855 default:
856 return(AE_BAD_PARAMETER);
857 break;
858 }
859
860 return(status);
861 }
862
863
864 /****************************************************************************
865 *
866 * FUNCTION: sm_osl_init
867 *
868 * PARAMETERS: <none>
869 *
870 * RETURN: 0: Success
871 *
872 * DESCRIPTION: Module initialization.
873 *
874 ****************************************************************************/
875
876 static int __init
877 sm_osl_init (void)
878 {
879 acpi_status status = AE_OK;
880
881 /* abort if no busmgr */
882 if (!bm_proc_root)
883 return -ENODEV;
884
885 sm_proc_root = bm_proc_root;
886 if (!sm_proc_root) {
887 status = AE_ERROR;
888 }
889 else {
890 status = sm_initialize();
891 }
892
893 return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
894 }
895
896
897 /****************************************************************************
898 *
899 * FUNCTION: sm_osl_cleanup
900 *
901 * PARAMETERS: <none>
902 *
903 * RETURN: <none>
904 *
905 * DESCRIPTION: Module cleanup.
906 *
907 ****************************************************************************/
908
909 static void __exit
910 sm_osl_cleanup (void)
911 {
912 sm_terminate();
913
914 return;
915 }
916
917
918 module_init(sm_osl_init);
919 module_exit(sm_osl_cleanup);
920