1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200#include <linux/config.h>
201#include <linux/module.h>
202
203#include <linux/poll.h>
204#include <linux/types.h>
205#include <linux/stddef.h>
206#include <linux/timer.h>
207#include <linux/fcntl.h>
208#include <linux/slab.h>
209#include <linux/stat.h>
210#include <linux/proc_fs.h>
211#include <linux/miscdevice.h>
212#include <linux/apm_bios.h>
213#include <linux/init.h>
214#include <linux/sched.h>
215#include <linux/pm.h>
216#include <linux/kernel.h>
217#include <linux/smp_lock.h>
218
219#include <asm/system.h>
220#include <asm/uaccess.h>
221#include <asm/desc.h>
222
223#include <linux/sysrq.h>
224
225extern unsigned long get_cmos_time(void);
226extern void machine_real_restart(unsigned char *, int);
227
228#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
229extern int (*console_blank_hook)(int);
230#endif
231
232
233
234
235
236#define APM_MINOR_DEV 134
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283#define ALWAYS_CALL_BUSY 1
284
285
286
287
288
289
290#define APM_ZERO_SEGS
291
292
293
294
295
296
297
298
299
300
301#define APM_RELAX_SEGMENTS
302
303
304
305
306
307
308#undef INIT_TIMER_AFTER_SUSPEND
309
310#ifdef INIT_TIMER_AFTER_SUSPEND
311#include <linux/timex.h>
312#include <asm/io.h>
313#include <linux/delay.h>
314#endif
315
316
317
318
319#define APM_CHECK_TIMEOUT (HZ)
320
321
322
323
324#define DEFAULT_BOUNCE_INTERVAL (3 * HZ)
325
326
327
328
329#define savesegment(seg, where) \
330 __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
331
332
333
334
335#define APM_MAX_EVENTS 20
336
337
338
339
340struct apm_user {
341 int magic;
342 struct apm_user * next;
343 int suser: 1;
344 int writer: 1;
345 int reader: 1;
346 int suspend_wait: 1;
347 int suspend_result;
348 int suspends_pending;
349 int standbys_pending;
350 int suspends_read;
351 int standbys_read;
352 int event_head;
353 int event_tail;
354 apm_event_t events[APM_MAX_EVENTS];
355};
356
357
358
359
360#define APM_BIOS_MAGIC 0x4101
361
362
363
364
365#ifdef CONFIG_APM_CPU_IDLE
366#define DEFAULT_IDLE_THRESHOLD 95
367#else
368#define DEFAULT_IDLE_THRESHOLD 100
369#endif
370#define DEFAULT_IDLE_PERIOD (100 / 3)
371
372
373
374
375static struct {
376 unsigned long offset;
377 unsigned short segment;
378} apm_bios_entry;
379static int clock_slowed;
380static int idle_threshold = DEFAULT_IDLE_THRESHOLD;
381static int idle_period = DEFAULT_IDLE_PERIOD;
382static int set_pm_idle;
383static int suspends_pending;
384static int standbys_pending;
385static int ignore_sys_suspend;
386static int ignore_normal_resume;
387static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
388
389#ifdef CONFIG_APM_RTC_IS_GMT
390# define clock_cmos_diff 0
391# define got_clock_diff 1
392#else
393static long clock_cmos_diff;
394static int got_clock_diff;
395#endif
396static int debug;
397static int smp = 0;
398static int apm_disabled = -1;
399#ifdef CONFIG_SMP
400static int power_off;
401#else
402static int power_off = 1;
403#endif
404#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
405static int realmode_power_off = 1;
406#else
407static int realmode_power_off;
408#endif
409static int exit_kapmd;
410static int kapmd_running;
411#ifdef CONFIG_APM_ALLOW_INTS
412static int allow_ints = 1;
413#else
414static int allow_ints;
415#endif
416static int broken_psr;
417
418static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
419static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
420static struct apm_user * user_list;
421
422static char driver_version[] = "1.16";
423
424
425
426
427
428static char * apm_event_name[] = {
429 "system standby",
430 "system suspend",
431 "normal resume",
432 "critical resume",
433 "low battery",
434 "power status change",
435 "update time",
436 "critical suspend",
437 "user standby",
438 "user suspend",
439 "system standby resume",
440 "capabilities change"
441};
442#define NR_APM_EVENT_NAME \
443 (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
444
445typedef struct lookup_t {
446 int key;
447 char * msg;
448} lookup_t;
449
450
451
452
453
454
455static const lookup_t error_table[] = {
456
457 { APM_DISABLED, "Power management disabled" },
458 { APM_CONNECTED, "Real mode interface already connected" },
459 { APM_NOT_CONNECTED, "Interface not connected" },
460 { APM_16_CONNECTED, "16 bit interface already connected" },
461
462 { APM_32_CONNECTED, "32 bit interface already connected" },
463 { APM_32_UNSUPPORTED, "32 bit interface not supported" },
464 { APM_BAD_DEVICE, "Unrecognized device ID" },
465 { APM_BAD_PARAM, "Parameter out of range" },
466 { APM_NOT_ENGAGED, "Interface not engaged" },
467 { APM_BAD_FUNCTION, "Function not supported" },
468 { APM_RESUME_DISABLED, "Resume timer disabled" },
469 { APM_BAD_STATE, "Unable to enter requested state" },
470
471 { APM_NO_ERROR, "BIOS did not set a return code" },
472 { APM_NOT_PRESENT, "No APM present" }
473};
474#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
475
476
477
478
479
480
481
482
483
484
485static void apm_error(char *str, int err)
486{
487 int i;
488
489 for (i = 0; i < ERROR_COUNT; i++)
490 if (error_table[i].key == err) break;
491 if (i < ERROR_COUNT)
492 printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
493 else
494 printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
495 str, err);
496}
497
498
499
500
501
502#ifdef CONFIG_SMP
503
504static unsigned long apm_save_cpus(void)
505{
506 unsigned long x = current->cpus_allowed;
507
508 if (cpu_number_map(smp_processor_id()) != 0) {
509 set_cpus_allowed(current, 1 << cpu_logical_map(0));
510 if (unlikely(cpu_number_map(smp_processor_id()) != 0))
511 BUG();
512 }
513 return x;
514}
515
516static inline void apm_restore_cpus(unsigned long mask)
517{
518 set_cpus_allowed(current, mask);
519}
520
521#else
522
523
524
525
526
527#define apm_save_cpus() 0
528#define apm_restore_cpus(x) (void)(x)
529
530#endif
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548#define APM_DO_CLI \
549 if (apm_info.allow_ints) \
550 __sti(); \
551 else \
552 __cli();
553
554#ifdef APM_ZERO_SEGS
555# define APM_DECL_SEGS \
556 unsigned int saved_fs; unsigned int saved_gs;
557# define APM_DO_SAVE_SEGS \
558 savesegment(fs, saved_fs); savesegment(gs, saved_gs)
559# define APM_DO_ZERO_SEGS \
560 "pushl %%ds\n\t" \
561 "pushl %%es\n\t" \
562 "xorl %%edx, %%edx\n\t" \
563 "mov %%dx, %%ds\n\t" \
564 "mov %%dx, %%es\n\t" \
565 "mov %%dx, %%fs\n\t" \
566 "mov %%dx, %%gs\n\t"
567# define APM_DO_POP_SEGS \
568 "popl %%es\n\t" \
569 "popl %%ds\n\t"
570# define APM_DO_RESTORE_SEGS \
571 loadsegment(fs, saved_fs); loadsegment(gs, saved_gs)
572#else
573# define APM_DECL_SEGS
574# define APM_DO_SAVE_SEGS
575# define APM_DO_ZERO_SEGS
576# define APM_DO_POP_SEGS
577# define APM_DO_RESTORE_SEGS
578#endif
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
601 u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
602{
603 APM_DECL_SEGS
604 unsigned long flags;
605 unsigned long cpus = apm_save_cpus();
606
607 __save_flags(flags);
608 APM_DO_CLI;
609 APM_DO_SAVE_SEGS;
610
611
612
613
614 __asm__ __volatile__(APM_DO_ZERO_SEGS
615 "pushl %%edi\n\t"
616 "pushl %%ebp\n\t"
617 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
618 "setc %%al\n\t"
619 "popl %%ebp\n\t"
620 "popl %%edi\n\t"
621 APM_DO_POP_SEGS
622 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
623 "=S" (*esi)
624 : "a" (func), "b" (ebx_in), "c" (ecx_in)
625 : "memory", "cc");
626 APM_DO_RESTORE_SEGS;
627 __restore_flags(flags);
628
629 apm_restore_cpus(cpus);
630
631 return *eax & 0xff;
632}
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
649{
650 u8 error;
651 APM_DECL_SEGS
652 unsigned long flags;
653
654 unsigned long cpus = apm_save_cpus();
655
656 __save_flags(flags);
657 APM_DO_CLI;
658 APM_DO_SAVE_SEGS;
659 {
660 int cx, dx, si;
661
662
663
664
665
666 __asm__ __volatile__(APM_DO_ZERO_SEGS
667 "pushl %%edi\n\t"
668 "pushl %%ebp\n\t"
669 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
670 "setc %%bl\n\t"
671 "popl %%ebp\n\t"
672 "popl %%edi\n\t"
673 APM_DO_POP_SEGS
674 : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
675 "=S" (si)
676 : "a" (func), "b" (ebx_in), "c" (ecx_in)
677 : "memory", "cc");
678 }
679 APM_DO_RESTORE_SEGS;
680 __restore_flags(flags);
681
682 apm_restore_cpus(cpus);
683
684 return error;
685}
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703static int __init apm_driver_version(u_short *val)
704{
705 u32 eax;
706
707 if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax))
708 return (eax >> 8) & 0xff;
709 *val = eax;
710 return APM_SUCCESS;
711}
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
731{
732 u32 eax;
733 u32 ebx;
734 u32 ecx;
735 u32 dummy;
736
737 if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx,
738 &dummy, &dummy))
739 return (eax >> 8) & 0xff;
740 *event = ebx;
741 if (apm_info.connection_version < 0x0102)
742 *info = ~0;
743 else
744 *info = ecx;
745 return APM_SUCCESS;
746}
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762static int set_power_state(u_short what, u_short state)
763{
764 u32 eax;
765
766 if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax))
767 return (eax >> 8) & 0xff;
768 return APM_SUCCESS;
769}
770
771
772
773
774
775
776
777
778static int set_system_power_state(u_short state)
779{
780 return set_power_state(APM_DEVICE_ALL, state);
781}
782
783
784
785
786
787
788
789
790
791
792static int apm_do_idle(void)
793{
794 u32 eax;
795
796 if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
797 static unsigned long t;
798
799
800
801
802 if (++t < 5) {
803 printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
804 (eax >> 8) & 0xff);
805 }
806 return -1;
807 }
808 clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
809 return clock_slowed;
810}
811
812
813
814
815
816
817
818static void apm_do_busy(void)
819{
820 u32 dummy;
821
822 if (clock_slowed || ALWAYS_CALL_BUSY) {
823 (void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy);
824 clock_slowed = 0;
825 }
826}
827
828
829
830
831
832
833
834#define IDLE_CALC_LIMIT (HZ * 100)
835#define IDLE_LEAKY_MAX 16
836
837static void (*original_pm_idle)(void);
838
839extern void default_idle(void);
840
841
842
843
844
845
846
847
848
849static void apm_cpu_idle(void)
850{
851 static int use_apm_idle;
852 static unsigned int last_jiffies;
853 static unsigned int last_stime;
854
855 int apm_idle_done = 0;
856 unsigned int jiffies_since_last_check = jiffies - last_jiffies;
857 unsigned int bucket;
858
859recalc:
860 if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
861 use_apm_idle = 0;
862 last_jiffies = jiffies;
863 last_stime = current->times.tms_stime;
864 } else if (jiffies_since_last_check > idle_period) {
865 unsigned int idle_percentage;
866
867 idle_percentage = current->times.tms_stime - last_stime;
868 idle_percentage *= 100;
869 idle_percentage /= jiffies_since_last_check;
870 use_apm_idle = (idle_percentage > idle_threshold);
871 last_jiffies = jiffies;
872 last_stime = current->times.tms_stime;
873 }
874
875 bucket = IDLE_LEAKY_MAX;
876
877 while (!current->need_resched) {
878 if (use_apm_idle) {
879 unsigned int t;
880
881 t = jiffies;
882 switch (apm_do_idle()) {
883 case 0: apm_idle_done = 1;
884 if (t != jiffies) {
885 if (bucket) {
886 bucket = IDLE_LEAKY_MAX;
887 continue;
888 }
889 } else if (bucket) {
890 bucket--;
891 continue;
892 }
893 break;
894 case 1: apm_idle_done = 1;
895 break;
896 default:
897 break;
898 }
899 }
900 if (original_pm_idle)
901 original_pm_idle();
902 else
903 default_idle();
904 jiffies_since_last_check = jiffies - last_jiffies;
905 if (jiffies_since_last_check > idle_period)
906 goto recalc;
907 }
908
909 if (apm_idle_done)
910 apm_do_busy();
911}
912
913
914
915
916
917
918
919
920
921
922
923static void apm_power_off(void)
924{
925 unsigned char po_bios_call[] = {
926 0xb8, 0x00, 0x10,
927 0x8e, 0xd0,
928 0xbc, 0x00, 0xf0,
929 0xb8, 0x07, 0x53,
930 0xbb, 0x01, 0x00,
931 0xb9, 0x03, 0x00,
932 0xcd, 0x15
933 };
934
935
936
937
938 if (apm_info.realmode_power_off)
939 {
940 (void)apm_save_cpus();
941 machine_real_restart(po_bios_call, sizeof(po_bios_call));
942
943 }
944 else
945 (void) set_system_power_state(APM_STATE_OFF);
946}
947
948
949
950
951
952
953
954
955
956
957
958
959void handle_poweroff (int key, struct pt_regs *pt_regs,
960 struct kbd_struct *kbd, struct tty_struct *tty) {
961 apm_power_off();
962}
963
964struct sysrq_key_op sysrq_poweroff_op = {
965 handler: handle_poweroff,
966 help_msg: "Off",
967 action_msg: "Power Off\n"
968};
969
970
971#ifdef CONFIG_APM_DO_ENABLE
972
973
974
975
976
977
978
979
980static int apm_enable_power_management(int enable)
981{
982 u32 eax;
983
984 if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
985 return APM_NOT_ENGAGED;
986 if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
987 enable, &eax))
988 return (eax >> 8) & 0xff;
989 if (enable)
990 apm_info.bios.flags &= ~APM_BIOS_DISABLED;
991 else
992 apm_info.bios.flags |= APM_BIOS_DISABLED;
993 return APM_SUCCESS;
994}
995#endif
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
1012{
1013 u32 eax;
1014 u32 ebx;
1015 u32 ecx;
1016 u32 edx;
1017 u32 dummy;
1018
1019 if (apm_info.get_power_status_broken)
1020 return APM_32_UNSUPPORTED;
1021 if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
1022 &eax, &ebx, &ecx, &edx, &dummy))
1023 return (eax >> 8) & 0xff;
1024 *status = ebx;
1025 *bat = ecx;
1026 if (apm_info.get_power_status_swabinminutes) {
1027 *life = swab16((u16)edx);
1028 *life |= 0x8000;
1029 } else
1030 *life = edx;
1031 return APM_SUCCESS;
1032}
1033
1034#if 0
1035static int apm_get_battery_status(u_short which, u_short *status,
1036 u_short *bat, u_short *life, u_short *nbat)
1037{
1038 u32 eax;
1039 u32 ebx;
1040 u32 ecx;
1041 u32 edx;
1042 u32 esi;
1043
1044 if (apm_info.connection_version < 0x0102) {
1045
1046 if (which != 1)
1047 return APM_BAD_DEVICE;
1048 *nbat = 1;
1049 return apm_get_power_status(status, bat, life);
1050 }
1051
1052 if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
1053 &ebx, &ecx, &edx, &esi))
1054 return (eax >> 8) & 0xff;
1055 *status = ebx;
1056 *bat = ecx;
1057 *life = edx;
1058 *nbat = esi;
1059 return APM_SUCCESS;
1060}
1061#endif
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072static int apm_engage_power_management(u_short device, int enable)
1073{
1074 u32 eax;
1075
1076 if ((enable == 0) && (device == APM_DEVICE_ALL)
1077 && (apm_info.bios.flags & APM_BIOS_DISABLED))
1078 return APM_DISABLED;
1079 if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
1080 return (eax >> 8) & 0xff;
1081 if (device == APM_DEVICE_ALL) {
1082 if (enable)
1083 apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
1084 else
1085 apm_info.bios.flags |= APM_BIOS_DISENGAGED;
1086 }
1087 return APM_SUCCESS;
1088}
1089
1090#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102static int apm_console_blank(int blank)
1103{
1104 int error;
1105 u_short state;
1106
1107 state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
1108
1109 error = set_power_state(0x100, state);
1110 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
1111
1112 error = set_power_state(0x1ff, state);
1113 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
1114
1115 error = set_power_state(0x101, state);
1116 }
1117 if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
1118 return 1;
1119 if (error == APM_NOT_ENGAGED) {
1120 static int tried;
1121 int eng_error;
1122 if (tried++ == 0) {
1123 eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1124 if (eng_error) {
1125 apm_error("set display", error);
1126 apm_error("engage interface", eng_error);
1127 return 0;
1128 } else
1129 return apm_console_blank(blank);
1130 }
1131 }
1132 apm_error("set display", error);
1133 return 0;
1134}
1135#endif
1136
1137static int queue_empty(struct apm_user *as)
1138{
1139 return as->event_head == as->event_tail;
1140}
1141
1142static apm_event_t get_queued_event(struct apm_user *as)
1143{
1144 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
1145 return as->events[as->event_tail];
1146}
1147
1148static void queue_event(apm_event_t event, struct apm_user *sender)
1149{
1150 struct apm_user * as;
1151
1152 if (user_list == NULL)
1153 return;
1154 for (as = user_list; as != NULL; as = as->next) {
1155 if ((as == sender) || (!as->reader))
1156 continue;
1157 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
1158 if (as->event_head == as->event_tail) {
1159 static int notified;
1160
1161 if (notified++ == 0)
1162 printk(KERN_ERR "apm: an event queue overflowed\n");
1163 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
1164 }
1165 as->events[as->event_head] = event;
1166 if ((!as->suser) || (!as->writer))
1167 continue;
1168 switch (event) {
1169 case APM_SYS_SUSPEND:
1170 case APM_USER_SUSPEND:
1171 as->suspends_pending++;
1172 suspends_pending++;
1173 break;
1174
1175 case APM_SYS_STANDBY:
1176 case APM_USER_STANDBY:
1177 as->standbys_pending++;
1178 standbys_pending++;
1179 break;
1180 }
1181 }
1182 wake_up_interruptible(&apm_waitqueue);
1183}
1184
1185static void set_time(void)
1186{
1187 unsigned long flags;
1188
1189 if (got_clock_diff) {
1190 save_flags(flags);
1191 cli();
1192 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
1193 restore_flags(flags);
1194 }
1195}
1196
1197static void get_time_diff(void)
1198{
1199#ifndef CONFIG_APM_RTC_IS_GMT
1200 unsigned long flags;
1201
1202
1203
1204
1205 save_flags(flags);
1206 clock_cmos_diff = -get_cmos_time();
1207 cli();
1208 clock_cmos_diff += CURRENT_TIME;
1209 got_clock_diff = 1;
1210 restore_flags(flags);
1211#endif
1212}
1213
1214static void reinit_timer(void)
1215{
1216#ifdef INIT_TIMER_AFTER_SUSPEND
1217 unsigned long flags;
1218
1219 save_flags(flags);
1220 cli();
1221
1222 outb_p(0x34,0x43);
1223 udelay(10);
1224 outb_p(LATCH & 0xff , 0x40);
1225 udelay(10);
1226 outb(LATCH >> 8 , 0x40);
1227 udelay(10);
1228 restore_flags(flags);
1229#endif
1230}
1231
1232static int suspend(int vetoable)
1233{
1234 int err;
1235 struct apm_user *as;
1236
1237 if (pm_send_all(PM_SUSPEND, (void *)3)) {
1238
1239 if (vetoable) {
1240 if (apm_info.connection_version > 0x100)
1241 set_system_power_state(APM_STATE_REJECT);
1242 err = -EBUSY;
1243 ignore_sys_suspend = 0;
1244 printk(KERN_WARNING "apm: suspend was vetoed.\n");
1245 goto out;
1246 }
1247 printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
1248 }
1249 get_time_diff();
1250 __cli();
1251 err = set_system_power_state(APM_STATE_SUSPEND);
1252 reinit_timer();
1253 set_time();
1254 ignore_normal_resume = 1;
1255 __sti();
1256 if (err == APM_NO_ERROR)
1257 err = APM_SUCCESS;
1258 if (err != APM_SUCCESS)
1259 apm_error("suspend", err);
1260 err = (err == APM_SUCCESS) ? 0 : -EIO;
1261 pm_send_all(PM_RESUME, (void *)0);
1262 queue_event(APM_NORMAL_RESUME, NULL);
1263 out:
1264 for (as = user_list; as != NULL; as = as->next) {
1265 as->suspend_wait = 0;
1266 as->suspend_result = err;
1267 }
1268 wake_up_interruptible(&apm_suspend_waitqueue);
1269 return err;
1270}
1271
1272static void standby(void)
1273{
1274 int err;
1275
1276
1277 get_time_diff();
1278 err = set_system_power_state(APM_STATE_STANDBY);
1279 if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
1280 apm_error("standby", err);
1281}
1282
1283static apm_event_t get_event(void)
1284{
1285 int error;
1286 apm_event_t event;
1287 apm_eventinfo_t info;
1288
1289 static int notified;
1290
1291
1292 error = apm_get_event(&event, &info);
1293 if (error == APM_SUCCESS)
1294 return event;
1295
1296 if ((error != APM_NO_EVENTS) && (notified++ == 0))
1297 apm_error("get_event", error);
1298
1299 return 0;
1300}
1301
1302static void check_events(void)
1303{
1304 apm_event_t event;
1305 static unsigned long last_resume;
1306 static int ignore_bounce;
1307
1308 while ((event = get_event()) != 0) {
1309 if (debug) {
1310 if (event <= NR_APM_EVENT_NAME)
1311 printk(KERN_DEBUG "apm: received %s notify\n",
1312 apm_event_name[event - 1]);
1313 else
1314 printk(KERN_DEBUG "apm: received unknown "
1315 "event 0x%02x\n", event);
1316 }
1317 if (ignore_bounce
1318 && ((jiffies - last_resume) > bounce_interval))
1319 ignore_bounce = 0;
1320
1321 switch (event) {
1322 case APM_SYS_STANDBY:
1323 case APM_USER_STANDBY:
1324 queue_event(event, NULL);
1325 if (standbys_pending <= 0)
1326 standby();
1327 break;
1328
1329 case APM_USER_SUSPEND:
1330#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
1331 if (apm_info.connection_version > 0x100)
1332 set_system_power_state(APM_STATE_REJECT);
1333 break;
1334#endif
1335 case APM_SYS_SUSPEND:
1336 if (ignore_bounce) {
1337 if (apm_info.connection_version > 0x100)
1338 set_system_power_state(APM_STATE_REJECT);
1339 break;
1340 }
1341
1342
1343
1344
1345
1346
1347
1348
1349 if (ignore_sys_suspend)
1350 return;
1351 ignore_sys_suspend = 1;
1352 queue_event(event, NULL);
1353 if (suspends_pending <= 0)
1354 (void) suspend(1);
1355 break;
1356
1357 case APM_NORMAL_RESUME:
1358 case APM_CRITICAL_RESUME:
1359 case APM_STANDBY_RESUME:
1360 ignore_sys_suspend = 0;
1361 last_resume = jiffies;
1362 ignore_bounce = 1;
1363 if ((event != APM_NORMAL_RESUME)
1364 || (ignore_normal_resume == 0)) {
1365 set_time();
1366 pm_send_all(PM_RESUME, (void *)0);
1367 queue_event(event, NULL);
1368 }
1369 ignore_normal_resume = 0;
1370 break;
1371
1372 case APM_CAPABILITY_CHANGE:
1373 case APM_LOW_BATTERY:
1374 case APM_POWER_STATUS_CHANGE:
1375 queue_event(event, NULL);
1376
1377 break;
1378
1379 case APM_UPDATE_TIME:
1380 set_time();
1381 break;
1382
1383 case APM_CRITICAL_SUSPEND:
1384
1385
1386
1387 (void) suspend(0);
1388 break;
1389 }
1390 }
1391}
1392
1393static void apm_event_handler(void)
1394{
1395 static int pending_count = 4;
1396 int err;
1397
1398 if ((standbys_pending > 0) || (suspends_pending > 0)) {
1399 if ((apm_info.connection_version > 0x100) &&
1400 (pending_count-- <= 0)) {
1401 pending_count = 4;
1402 if (debug)
1403 printk(KERN_DEBUG "apm: setting state busy\n");
1404 err = set_system_power_state(APM_STATE_BUSY);
1405 if (err)
1406 apm_error("busy", err);
1407 }
1408 } else
1409 pending_count = 4;
1410 check_events();
1411}
1412
1413
1414
1415
1416
1417static void apm_mainloop(void)
1418{
1419 DECLARE_WAITQUEUE(wait, current);
1420
1421 add_wait_queue(&apm_waitqueue, &wait);
1422 set_current_state(TASK_INTERRUPTIBLE);
1423 for (;;) {
1424 schedule_timeout(APM_CHECK_TIMEOUT);
1425 if (exit_kapmd)
1426 break;
1427
1428
1429
1430
1431 set_current_state(TASK_INTERRUPTIBLE);
1432 apm_event_handler();
1433 }
1434 remove_wait_queue(&apm_waitqueue, &wait);
1435}
1436
1437static int check_apm_user(struct apm_user *as, const char *func)
1438{
1439 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
1440 printk(KERN_ERR "apm: %s passed bad filp\n", func);
1441 return 1;
1442 }
1443 return 0;
1444}
1445
1446static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
1447{
1448 struct apm_user * as;
1449 int i;
1450 apm_event_t event;
1451
1452 as = fp->private_data;
1453 if (check_apm_user(as, "read"))
1454 return -EIO;
1455 if ((int)count < sizeof(apm_event_t))
1456 return -EINVAL;
1457 if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
1458 return -EAGAIN;
1459 wait_event_interruptible(apm_waitqueue, !queue_empty(as));
1460 i = count;
1461 while ((i >= sizeof(event)) && !queue_empty(as)) {
1462 event = get_queued_event(as);
1463 if (copy_to_user(buf, &event, sizeof(event))) {
1464 if (i < count)
1465 break;
1466 return -EFAULT;
1467 }
1468 switch (event) {
1469 case APM_SYS_SUSPEND:
1470 case APM_USER_SUSPEND:
1471 as->suspends_read++;
1472 break;
1473
1474 case APM_SYS_STANDBY:
1475 case APM_USER_STANDBY:
1476 as->standbys_read++;
1477 break;
1478 }
1479 buf += sizeof(event);
1480 i -= sizeof(event);
1481 }
1482 if (i < count)
1483 return count - i;
1484 if (signal_pending(current))
1485 return -ERESTARTSYS;
1486 return 0;
1487}
1488
1489static unsigned int do_poll(struct file *fp, poll_table * wait)
1490{
1491 struct apm_user * as;
1492
1493 as = fp->private_data;
1494 if (check_apm_user(as, "poll"))
1495 return 0;
1496 poll_wait(fp, &apm_waitqueue, wait);
1497 if (!queue_empty(as))
1498 return POLLIN | POLLRDNORM;
1499 return 0;
1500}
1501
1502static int do_ioctl(struct inode * inode, struct file *filp,
1503 u_int cmd, u_long arg)
1504{
1505 struct apm_user * as;
1506
1507 as = filp->private_data;
1508 if (check_apm_user(as, "ioctl"))
1509 return -EIO;
1510 if ((!as->suser) || (!as->writer))
1511 return -EPERM;
1512 switch (cmd) {
1513 case APM_IOC_STANDBY:
1514 if (as->standbys_read > 0) {
1515 as->standbys_read--;
1516 as->standbys_pending--;
1517 standbys_pending--;
1518 } else
1519 queue_event(APM_USER_STANDBY, as);
1520 if (standbys_pending <= 0)
1521 standby();
1522 break;
1523 case APM_IOC_SUSPEND:
1524 if (as->suspends_read > 0) {
1525 as->suspends_read--;
1526 as->suspends_pending--;
1527 suspends_pending--;
1528 } else
1529 queue_event(APM_USER_SUSPEND, as);
1530 if (suspends_pending <= 0) {
1531 return suspend(1);
1532 } else {
1533 as->suspend_wait = 1;
1534 wait_event_interruptible(apm_suspend_waitqueue,
1535 as->suspend_wait == 0);
1536 return as->suspend_result;
1537 }
1538 break;
1539 default:
1540 return -EINVAL;
1541 }
1542 return 0;
1543}
1544
1545static int do_release(struct inode * inode, struct file * filp)
1546{
1547 struct apm_user * as;
1548
1549 as = filp->private_data;
1550 if (check_apm_user(as, "release"))
1551 return 0;
1552 filp->private_data = NULL;
1553 lock_kernel();
1554 if (as->standbys_pending > 0) {
1555 standbys_pending -= as->standbys_pending;
1556 if (standbys_pending <= 0)
1557 standby();
1558 }
1559 if (as->suspends_pending > 0) {
1560 suspends_pending -= as->suspends_pending;
1561 if (suspends_pending <= 0)
1562 (void) suspend(1);
1563 }
1564 if (user_list == as)
1565 user_list = as->next;
1566 else {
1567 struct apm_user * as1;
1568
1569 for (as1 = user_list;
1570 (as1 != NULL) && (as1->next != as);
1571 as1 = as1->next)
1572 ;
1573 if (as1 == NULL)
1574 printk(KERN_ERR "apm: filp not in user list\n");
1575 else
1576 as1->next = as->next;
1577 }
1578 unlock_kernel();
1579 kfree(as);
1580 return 0;
1581}
1582
1583static int do_open(struct inode * inode, struct file * filp)
1584{
1585 struct apm_user * as;
1586
1587 as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
1588 if (as == NULL) {
1589 printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
1590 sizeof(*as));
1591 return -ENOMEM;
1592 }
1593 as->magic = APM_BIOS_MAGIC;
1594 as->event_tail = as->event_head = 0;
1595 as->suspends_pending = as->standbys_pending = 0;
1596 as->suspends_read = as->standbys_read = 0;
1597
1598
1599
1600
1601
1602
1603
1604 as->suser = capable(CAP_SYS_ADMIN);
1605 as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
1606 as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
1607 as->next = user_list;
1608 user_list = as;
1609 filp->private_data = as;
1610 return 0;
1611}
1612
1613static int apm_get_info(char *buf, char **start, off_t fpos, int length)
1614{
1615 char * p;
1616 unsigned short bx;
1617 unsigned short cx;
1618 unsigned short dx;
1619 int error;
1620 unsigned short ac_line_status = 0xff;
1621 unsigned short battery_status = 0xff;
1622 unsigned short battery_flag = 0xff;
1623 int percentage = -1;
1624 int time_units = -1;
1625 char *units = "?";
1626
1627 p = buf;
1628
1629 if ((smp_num_cpus == 1 || smp) &&
1630 !(error = apm_get_power_status(&bx, &cx, &dx))) {
1631 ac_line_status = (bx >> 8) & 0xff;
1632 battery_status = bx & 0xff;
1633 if ((cx & 0xff) != 0xff)
1634 percentage = cx & 0xff;
1635
1636 if (apm_info.connection_version > 0x100) {
1637 battery_flag = (cx >> 8) & 0xff;
1638 if (dx != 0xffff) {
1639 units = (dx & 0x8000) ? "min" : "sec";
1640 time_units = dx & 0x7fff;
1641 }
1642 }
1643 }
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1683 driver_version,
1684 (apm_info.bios.version >> 8) & 0xff,
1685 apm_info.bios.version & 0xff,
1686 apm_info.bios.flags,
1687 ac_line_status,
1688 battery_status,
1689 battery_flag,
1690 percentage,
1691 time_units,
1692 units);
1693
1694 return p - buf;
1695}
1696
1697static int apm(void *unused)
1698{
1699 unsigned short bx;
1700 unsigned short cx;
1701 unsigned short dx;
1702 int error;
1703 char * power_stat;
1704 char * bat_stat;
1705
1706 kapmd_running = 1;
1707
1708 daemonize();
1709
1710 strcpy(current->comm, "kapmd");
1711 sigfillset(¤t->blocked);
1712
1713#ifdef CONFIG_SMP
1714
1715
1716
1717
1718
1719
1720 if (cpu_number_map(smp_processor_id()) != 0) {
1721 current->cpus_allowed = 1;
1722 schedule();
1723 if (unlikely(cpu_number_map(smp_processor_id()) != 0))
1724 BUG();
1725 }
1726#endif
1727
1728 if (apm_info.connection_version == 0) {
1729 apm_info.connection_version = apm_info.bios.version;
1730 if (apm_info.connection_version > 0x100) {
1731
1732
1733
1734 if (apm_info.connection_version > 0x0102)
1735 apm_info.connection_version = 0x0102;
1736 error = apm_driver_version(&apm_info.connection_version);
1737 if (error != APM_SUCCESS) {
1738 apm_error("driver version", error);
1739
1740 apm_info.connection_version = 0x100;
1741 }
1742 }
1743 }
1744
1745 if (debug)
1746 printk(KERN_INFO "apm: Connection version %d.%d\n",
1747 (apm_info.connection_version >> 8) & 0xff,
1748 apm_info.connection_version & 0xff);
1749
1750#ifdef CONFIG_APM_DO_ENABLE
1751 if (apm_info.bios.flags & APM_BIOS_DISABLED) {
1752
1753
1754
1755
1756
1757 error = apm_enable_power_management(1);
1758 if (error) {
1759 apm_error("enable power management", error);
1760 return -1;
1761 }
1762 }
1763#endif
1764
1765 if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
1766 && (apm_info.connection_version > 0x0100)) {
1767 error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1768 if (error) {
1769 apm_error("engage power management", error);
1770 return -1;
1771 }
1772 }
1773
1774 if (debug && (smp_num_cpus == 1 || smp )) {
1775 error = apm_get_power_status(&bx, &cx, &dx);
1776 if (error)
1777 printk(KERN_INFO "apm: power status not available\n");
1778 else {
1779 switch ((bx >> 8) & 0xff) {
1780 case 0: power_stat = "off line"; break;
1781 case 1: power_stat = "on line"; break;
1782 case 2: power_stat = "on backup power"; break;
1783 default: power_stat = "unknown"; break;
1784 }
1785 switch (bx & 0xff) {
1786 case 0: bat_stat = "high"; break;
1787 case 1: bat_stat = "low"; break;
1788 case 2: bat_stat = "critical"; break;
1789 case 3: bat_stat = "charging"; break;
1790 default: bat_stat = "unknown"; break;
1791 }
1792 printk(KERN_INFO
1793 "apm: AC %s, battery status %s, battery life ",
1794 power_stat, bat_stat);
1795 if ((cx & 0xff) == 0xff)
1796 printk("unknown\n");
1797 else
1798 printk("%d%%\n", cx & 0xff);
1799 if (apm_info.connection_version > 0x100) {
1800 printk(KERN_INFO
1801 "apm: battery flag 0x%02x, battery life ",
1802 (cx >> 8) & 0xff);
1803 if (dx == 0xffff)
1804 printk("unknown\n");
1805 else
1806 printk("%d %s\n", dx & 0x7fff,
1807 (dx & 0x8000) ?
1808 "minutes" : "seconds");
1809 }
1810 }
1811 }
1812
1813
1814 if (power_off)
1815 pm_power_off = apm_power_off;
1816 register_sysrq_key('o', &sysrq_poweroff_op);
1817
1818 if (smp_num_cpus == 1 || smp) {
1819#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1820 console_blank_hook = apm_console_blank;
1821#endif
1822 apm_mainloop();
1823#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1824 console_blank_hook = NULL;
1825#endif
1826 }
1827 kapmd_running = 0;
1828
1829 return 0;
1830}
1831
1832#ifndef MODULE
1833static int __init apm_setup(char *str)
1834{
1835 int invert;
1836
1837 while ((str != NULL) && (*str != '\0')) {
1838 if (strncmp(str, "off", 3) == 0)
1839 apm_disabled = 1;
1840 if (strncmp(str, "on", 2) == 0)
1841 apm_disabled = 0;
1842 if ((strncmp(str, "bounce-interval=", 16) == 0) ||
1843 (strncmp(str, "bounce_interval=", 16) == 0))
1844 bounce_interval = simple_strtol(str + 16, NULL, 0);
1845 if ((strncmp(str, "idle-threshold=", 15) == 0) ||
1846 (strncmp(str, "idle_threshold=", 15) == 0))
1847 idle_threshold = simple_strtol(str + 15, NULL, 0);
1848 if ((strncmp(str, "idle-period=", 12) == 0) ||
1849 (strncmp(str, "idle_period=", 12) == 0))
1850 idle_period = simple_strtol(str + 12, NULL, 0);
1851 invert = (strncmp(str, "no-", 3) == 0) ||
1852 (strncmp(str, "no_", 3) == 0);
1853 if (invert)
1854 str += 3;
1855 if (strncmp(str, "debug", 5) == 0)
1856 debug = !invert;
1857 if (strncmp(str, "smp", 3) == 0)
1858 {
1859 smp = !invert;
1860 idle_threshold = 100;
1861 }
1862 if ((strncmp(str, "power-off", 9) == 0) ||
1863 (strncmp(str, "power_off", 9) == 0))
1864 power_off = !invert;
1865 if ((strncmp(str, "allow-ints", 10) == 0) ||
1866 (strncmp(str, "allow_ints", 10) == 0))
1867 apm_info.allow_ints = !invert;
1868 if ((strncmp(str, "broken-psr", 10) == 0) ||
1869 (strncmp(str, "broken_psr", 10) == 0))
1870 apm_info.get_power_status_broken = !invert;
1871 if ((strncmp(str, "realmode-power-off", 18) == 0) ||
1872 (strncmp(str, "realmode_power_off", 18) == 0))
1873 apm_info.realmode_power_off = !invert;
1874 str = strchr(str, ',');
1875 if (str != NULL)
1876 str += strspn(str, ", \t");
1877 }
1878 return 1;
1879}
1880
1881__setup("apm=", apm_setup);
1882#endif
1883
1884static struct file_operations apm_bios_fops = {
1885 owner: THIS_MODULE,
1886 read: do_read,
1887 poll: do_poll,
1888 ioctl: do_ioctl,
1889 open: do_open,
1890 release: do_release,
1891};
1892
1893static struct miscdevice apm_device = {
1894 APM_MINOR_DEV,
1895 "apm_bios",
1896 &apm_bios_fops
1897};
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909static int __init apm_init(void)
1910{
1911 struct proc_dir_entry *apm_proc;
1912
1913 if (apm_info.bios.version == 0) {
1914 printk(KERN_INFO "apm: BIOS not found.\n");
1915 return -ENODEV;
1916 }
1917 printk(KERN_INFO
1918 "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
1919 ((apm_info.bios.version >> 8) & 0xff),
1920 (apm_info.bios.version & 0xff),
1921 apm_info.bios.flags,
1922 driver_version);
1923 if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
1924 printk(KERN_INFO "apm: no 32 bit BIOS support\n");
1925 return -ENODEV;
1926 }
1927
1928 if (allow_ints)
1929 apm_info.allow_ints = 1;
1930 if (broken_psr)
1931 apm_info.get_power_status_broken = 1;
1932 if (realmode_power_off)
1933 apm_info.realmode_power_off = 1;
1934
1935 if (apm_disabled != -1)
1936 apm_info.disabled = apm_disabled;
1937
1938
1939
1940
1941
1942 if (apm_info.bios.version == 0x001)
1943 apm_info.bios.version = 0x100;
1944
1945
1946 if (apm_info.bios.version < 0x102)
1947 apm_info.bios.cseg_16_len = 0;
1948
1949 if (debug) {
1950 printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
1951 apm_info.bios.cseg, apm_info.bios.offset,
1952 apm_info.bios.cseg_16, apm_info.bios.dseg);
1953 if (apm_info.bios.version > 0x100)
1954 printk(" cseg len %x, dseg len %x",
1955 apm_info.bios.cseg_len,
1956 apm_info.bios.dseg_len);
1957 if (apm_info.bios.version > 0x101)
1958 printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
1959 printk("\n");
1960 }
1961
1962 if (apm_info.disabled) {
1963 printk(KERN_NOTICE "apm: disabled on user request.\n");
1964 return -ENODEV;
1965 }
1966 if ((smp_num_cpus > 1) && !power_off && !smp) {
1967 printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
1968 return -ENODEV;
1969 }
1970 if (PM_IS_ACTIVE()) {
1971 printk(KERN_NOTICE "apm: overridden by ACPI.\n");
1972 return -ENODEV;
1973 }
1974 pm_active = 1;
1975
1976
1977
1978
1979
1980
1981
1982 set_base(gdt[APM_40 >> 3],
1983 __va((unsigned long)0x40 << 4));
1984 _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
1985
1986 apm_bios_entry.offset = apm_info.bios.offset;
1987 apm_bios_entry.segment = APM_CS;
1988 set_base(gdt[APM_CS >> 3],
1989 __va((unsigned long)apm_info.bios.cseg << 4));
1990 set_base(gdt[APM_CS_16 >> 3],
1991 __va((unsigned long)apm_info.bios.cseg_16 << 4));
1992 set_base(gdt[APM_DS >> 3],
1993 __va((unsigned long)apm_info.bios.dseg << 4));
1994#ifndef APM_RELAX_SEGMENTS
1995 if (apm_info.bios.version == 0x100) {
1996#endif
1997
1998 _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
1999
2000 _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
2001
2002 _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
2003#ifndef APM_RELAX_SEGMENTS
2004 } else {
2005 _set_limit((char *)&gdt[APM_CS >> 3],
2006 (apm_info.bios.cseg_len - 1) & 0xffff);
2007 _set_limit((char *)&gdt[APM_CS_16 >> 3],
2008 (apm_info.bios.cseg_16_len - 1) & 0xffff);
2009 _set_limit((char *)&gdt[APM_DS >> 3],
2010 (apm_info.bios.dseg_len - 1) & 0xffff);
2011 }
2012#endif
2013
2014 apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
2015 if (apm_proc)
2016 SET_MODULE_OWNER(apm_proc);
2017
2018 kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
2019
2020 if (smp_num_cpus > 1 && !smp) {
2021 printk(KERN_NOTICE
2022 "apm: disabled - APM is not SMP safe (power off active).\n");
2023 return 0;
2024 }
2025
2026 misc_register(&apm_device);
2027
2028 if (HZ != 100)
2029 idle_period = (idle_period * HZ) / 100;
2030 if (idle_threshold < 100) {
2031 original_pm_idle = pm_idle;
2032 pm_idle = apm_cpu_idle;
2033 set_pm_idle = 1;
2034 }
2035
2036 return 0;
2037}
2038
2039static void __exit apm_exit(void)
2040{
2041 int error;
2042
2043 if (set_pm_idle)
2044 pm_idle = original_pm_idle;
2045 if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
2046 && (apm_info.connection_version > 0x0100)) {
2047 error = apm_engage_power_management(APM_DEVICE_ALL, 0);
2048 if (error)
2049 apm_error("disengage power management", error);
2050 }
2051 misc_deregister(&apm_device);
2052 remove_proc_entry("apm", NULL);
2053 unregister_sysrq_key('o',&sysrq_poweroff_op);
2054 if (power_off)
2055 pm_power_off = NULL;
2056 exit_kapmd = 1;
2057 while (kapmd_running)
2058 schedule();
2059 pm_active = 0;
2060}
2061
2062module_init(apm_init);
2063module_exit(apm_exit);
2064
2065MODULE_AUTHOR("Stephen Rothwell");
2066MODULE_DESCRIPTION("Advanced Power Management");
2067MODULE_LICENSE("GPL");
2068MODULE_PARM(debug, "i");
2069MODULE_PARM_DESC(debug, "Enable debug mode");
2070MODULE_PARM(power_off, "i");
2071MODULE_PARM_DESC(power_off, "Enable power off");
2072MODULE_PARM(bounce_interval, "i");
2073MODULE_PARM_DESC(bounce_interval,
2074 "Set the number of ticks to ignore suspend bounces");
2075MODULE_PARM(allow_ints, "i");
2076MODULE_PARM_DESC(allow_ints, "Allow interrupts during BIOS calls");
2077MODULE_PARM(broken_psr, "i");
2078MODULE_PARM_DESC(broken_psr, "BIOS has a broken GetPowerStatus call");
2079MODULE_PARM(realmode_power_off, "i");
2080MODULE_PARM_DESC(realmode_power_off,
2081 "Switch to real mode before powering off");
2082MODULE_PARM(idle_threshold, "i");
2083MODULE_PARM_DESC(idle_threshold,
2084 "System idle percentage above which to make APM BIOS idle calls");
2085MODULE_PARM(idle_period, "i");
2086MODULE_PARM_DESC(idle_period,
2087 "Period (in sec/100) over which to caculate the idle percentage");
2088MODULE_PARM(smp, "i");
2089MODULE_PARM_DESC(smp,
2090 "Set this to enable APM use on an SMP platform. Use with caution on older systems");
2091
2092EXPORT_NO_SYMBOLS;
2093