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