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 if (apm_info.forbid_idle)
872 use_apm_idle = 0;
873 last_jiffies = jiffies;
874 last_stime = current->times.tms_stime;
875 }
876
877 bucket = IDLE_LEAKY_MAX;
878
879 while (!current->need_resched) {
880 if (use_apm_idle) {
881 unsigned int t;
882
883 t = jiffies;
884 switch (apm_do_idle()) {
885 case 0: apm_idle_done = 1;
886 if (t != jiffies) {
887 if (bucket) {
888 bucket = IDLE_LEAKY_MAX;
889 continue;
890 }
891 } else if (bucket) {
892 bucket--;
893 continue;
894 }
895 break;
896 case 1: apm_idle_done = 1;
897 break;
898 default:
899 break;
900 }
901 }
902 if (original_pm_idle)
903 original_pm_idle();
904 else
905 default_idle();
906 jiffies_since_last_check = jiffies - last_jiffies;
907 if (jiffies_since_last_check > idle_period)
908 goto recalc;
909 }
910
911 if (apm_idle_done)
912 apm_do_busy();
913}
914
915
916
917
918
919
920
921
922
923
924
925static void apm_power_off(void)
926{
927 unsigned char po_bios_call[] = {
928 0xb8, 0x00, 0x10,
929 0x8e, 0xd0,
930 0xbc, 0x00, 0xf0,
931 0xb8, 0x07, 0x53,
932 0xbb, 0x01, 0x00,
933 0xb9, 0x03, 0x00,
934 0xcd, 0x15
935 };
936
937
938
939
940 if (apm_info.realmode_power_off)
941 {
942 (void)apm_save_cpus();
943 machine_real_restart(po_bios_call, sizeof(po_bios_call));
944
945 }
946 else
947 (void) set_system_power_state(APM_STATE_OFF);
948}
949
950
951
952
953
954
955
956
957
958
959
960
961void handle_poweroff (int key, struct pt_regs *pt_regs,
962 struct kbd_struct *kbd, struct tty_struct *tty) {
963 apm_power_off();
964}
965
966struct sysrq_key_op sysrq_poweroff_op = {
967 handler: handle_poweroff,
968 help_msg: "Off",
969 action_msg: "Power Off\n"
970};
971
972
973#ifdef CONFIG_APM_DO_ENABLE
974
975
976
977
978
979
980
981
982static int apm_enable_power_management(int enable)
983{
984 u32 eax;
985
986 if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
987 return APM_NOT_ENGAGED;
988 if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
989 enable, &eax))
990 return (eax >> 8) & 0xff;
991 if (enable)
992 apm_info.bios.flags &= ~APM_BIOS_DISABLED;
993 else
994 apm_info.bios.flags |= APM_BIOS_DISABLED;
995 return APM_SUCCESS;
996}
997#endif
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
1014{
1015 u32 eax;
1016 u32 ebx;
1017 u32 ecx;
1018 u32 edx;
1019 u32 dummy;
1020
1021 if (apm_info.get_power_status_broken)
1022 return APM_32_UNSUPPORTED;
1023 if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
1024 &eax, &ebx, &ecx, &edx, &dummy))
1025 return (eax >> 8) & 0xff;
1026 *status = ebx;
1027 *bat = ecx;
1028 if (apm_info.get_power_status_swabinminutes) {
1029 *life = swab16((u16)edx);
1030 *life |= 0x8000;
1031 } else
1032 *life = edx;
1033 return APM_SUCCESS;
1034}
1035
1036#if 0
1037static int apm_get_battery_status(u_short which, u_short *status,
1038 u_short *bat, u_short *life, u_short *nbat)
1039{
1040 u32 eax;
1041 u32 ebx;
1042 u32 ecx;
1043 u32 edx;
1044 u32 esi;
1045
1046 if (apm_info.connection_version < 0x0102) {
1047
1048 if (which != 1)
1049 return APM_BAD_DEVICE;
1050 *nbat = 1;
1051 return apm_get_power_status(status, bat, life);
1052 }
1053
1054 if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
1055 &ebx, &ecx, &edx, &esi))
1056 return (eax >> 8) & 0xff;
1057 *status = ebx;
1058 *bat = ecx;
1059 *life = edx;
1060 *nbat = esi;
1061 return APM_SUCCESS;
1062}
1063#endif
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074static int apm_engage_power_management(u_short device, int enable)
1075{
1076 u32 eax;
1077
1078 if ((enable == 0) && (device == APM_DEVICE_ALL)
1079 && (apm_info.bios.flags & APM_BIOS_DISABLED))
1080 return APM_DISABLED;
1081 if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
1082 return (eax >> 8) & 0xff;
1083 if (device == APM_DEVICE_ALL) {
1084 if (enable)
1085 apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
1086 else
1087 apm_info.bios.flags |= APM_BIOS_DISENGAGED;
1088 }
1089 return APM_SUCCESS;
1090}
1091
1092#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104static int apm_console_blank(int blank)
1105{
1106 int error;
1107 u_short state;
1108
1109 state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
1110
1111 error = set_power_state(0x100, state);
1112 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
1113
1114 error = set_power_state(0x1ff, state);
1115 if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
1116
1117 error = set_power_state(0x101, state);
1118 }
1119 if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
1120 return 1;
1121 if (error == APM_NOT_ENGAGED) {
1122 static int tried;
1123 int eng_error;
1124 if (tried++ == 0) {
1125 eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1126 if (eng_error) {
1127 apm_error("set display", error);
1128 apm_error("engage interface", eng_error);
1129 return 0;
1130 } else
1131 return apm_console_blank(blank);
1132 }
1133 }
1134 apm_error("set display", error);
1135 return 0;
1136}
1137#endif
1138
1139static int queue_empty(struct apm_user *as)
1140{
1141 return as->event_head == as->event_tail;
1142}
1143
1144static apm_event_t get_queued_event(struct apm_user *as)
1145{
1146 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
1147 return as->events[as->event_tail];
1148}
1149
1150static void queue_event(apm_event_t event, struct apm_user *sender)
1151{
1152 struct apm_user * as;
1153
1154 if (user_list == NULL)
1155 return;
1156 for (as = user_list; as != NULL; as = as->next) {
1157 if ((as == sender) || (!as->reader))
1158 continue;
1159 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
1160 if (as->event_head == as->event_tail) {
1161 static int notified;
1162
1163 if (notified++ == 0)
1164 printk(KERN_ERR "apm: an event queue overflowed\n");
1165 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
1166 }
1167 as->events[as->event_head] = event;
1168 if ((!as->suser) || (!as->writer))
1169 continue;
1170 switch (event) {
1171 case APM_SYS_SUSPEND:
1172 case APM_USER_SUSPEND:
1173 as->suspends_pending++;
1174 suspends_pending++;
1175 break;
1176
1177 case APM_SYS_STANDBY:
1178 case APM_USER_STANDBY:
1179 as->standbys_pending++;
1180 standbys_pending++;
1181 break;
1182 }
1183 }
1184 wake_up_interruptible(&apm_waitqueue);
1185}
1186
1187static void set_time(void)
1188{
1189 unsigned long flags;
1190
1191 if (got_clock_diff) {
1192 save_flags(flags);
1193 cli();
1194 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
1195 restore_flags(flags);
1196 }
1197}
1198
1199static void get_time_diff(void)
1200{
1201#ifndef CONFIG_APM_RTC_IS_GMT
1202 unsigned long flags;
1203
1204
1205
1206
1207 save_flags(flags);
1208 clock_cmos_diff = -get_cmos_time();
1209 cli();
1210 clock_cmos_diff += CURRENT_TIME;
1211 got_clock_diff = 1;
1212 restore_flags(flags);
1213#endif
1214}
1215
1216static void reinit_timer(void)
1217{
1218#ifdef INIT_TIMER_AFTER_SUSPEND
1219 unsigned long flags;
1220
1221 save_flags(flags);
1222 cli();
1223
1224 outb_p(0x34,0x43);
1225 udelay(10);
1226 outb_p(LATCH & 0xff , 0x40);
1227 udelay(10);
1228 outb(LATCH >> 8 , 0x40);
1229 udelay(10);
1230 restore_flags(flags);
1231#endif
1232}
1233
1234static int suspend(int vetoable)
1235{
1236 int err;
1237 struct apm_user *as;
1238
1239 if (pm_send_all(PM_SUSPEND, (void *)3)) {
1240
1241 if (vetoable) {
1242 if (apm_info.connection_version > 0x100)
1243 set_system_power_state(APM_STATE_REJECT);
1244 err = -EBUSY;
1245 ignore_sys_suspend = 0;
1246 printk(KERN_WARNING "apm: suspend was vetoed.\n");
1247 goto out;
1248 }
1249 printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
1250 }
1251 get_time_diff();
1252 __cli();
1253 err = set_system_power_state(APM_STATE_SUSPEND);
1254 reinit_timer();
1255 set_time();
1256 ignore_normal_resume = 1;
1257 __sti();
1258 if (err == APM_NO_ERROR)
1259 err = APM_SUCCESS;
1260 if (err != APM_SUCCESS)
1261 apm_error("suspend", err);
1262 err = (err == APM_SUCCESS) ? 0 : -EIO;
1263 pm_send_all(PM_RESUME, (void *)0);
1264 queue_event(APM_NORMAL_RESUME, NULL);
1265 out:
1266 for (as = user_list; as != NULL; as = as->next) {
1267 as->suspend_wait = 0;
1268 as->suspend_result = err;
1269 }
1270 wake_up_interruptible(&apm_suspend_waitqueue);
1271 return err;
1272}
1273
1274static void standby(void)
1275{
1276 int err;
1277
1278
1279 get_time_diff();
1280 err = set_system_power_state(APM_STATE_STANDBY);
1281 if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
1282 apm_error("standby", err);
1283}
1284
1285static apm_event_t get_event(void)
1286{
1287 int error;
1288 apm_event_t event;
1289 apm_eventinfo_t info;
1290
1291 static int notified;
1292
1293
1294 error = apm_get_event(&event, &info);
1295 if (error == APM_SUCCESS)
1296 return event;
1297
1298 if ((error != APM_NO_EVENTS) && (notified++ == 0))
1299 apm_error("get_event", error);
1300
1301 return 0;
1302}
1303
1304static void check_events(void)
1305{
1306 apm_event_t event;
1307 static unsigned long last_resume;
1308 static int ignore_bounce;
1309
1310 while ((event = get_event()) != 0) {
1311 if (debug) {
1312 if (event <= NR_APM_EVENT_NAME)
1313 printk(KERN_DEBUG "apm: received %s notify\n",
1314 apm_event_name[event - 1]);
1315 else
1316 printk(KERN_DEBUG "apm: received unknown "
1317 "event 0x%02x\n", event);
1318 }
1319 if (ignore_bounce
1320 && ((jiffies - last_resume) > bounce_interval))
1321 ignore_bounce = 0;
1322
1323 switch (event) {
1324 case APM_SYS_STANDBY:
1325 case APM_USER_STANDBY:
1326 queue_event(event, NULL);
1327 if (standbys_pending <= 0)
1328 standby();
1329 break;
1330
1331 case APM_USER_SUSPEND:
1332#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
1333 if (apm_info.connection_version > 0x100)
1334 set_system_power_state(APM_STATE_REJECT);
1335 break;
1336#endif
1337 case APM_SYS_SUSPEND:
1338 if (ignore_bounce) {
1339 if (apm_info.connection_version > 0x100)
1340 set_system_power_state(APM_STATE_REJECT);
1341 break;
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351 if (ignore_sys_suspend)
1352 return;
1353 ignore_sys_suspend = 1;
1354 queue_event(event, NULL);
1355 if (suspends_pending <= 0)
1356 (void) suspend(1);
1357 break;
1358
1359 case APM_NORMAL_RESUME:
1360 case APM_CRITICAL_RESUME:
1361 case APM_STANDBY_RESUME:
1362 ignore_sys_suspend = 0;
1363 last_resume = jiffies;
1364 ignore_bounce = 1;
1365 if ((event != APM_NORMAL_RESUME)
1366 || (ignore_normal_resume == 0)) {
1367 set_time();
1368 pm_send_all(PM_RESUME, (void *)0);
1369 queue_event(event, NULL);
1370 }
1371 ignore_normal_resume = 0;
1372 break;
1373
1374 case APM_CAPABILITY_CHANGE:
1375 case APM_LOW_BATTERY:
1376 case APM_POWER_STATUS_CHANGE:
1377 queue_event(event, NULL);
1378
1379 break;
1380
1381 case APM_UPDATE_TIME:
1382 set_time();
1383 break;
1384
1385 case APM_CRITICAL_SUSPEND:
1386
1387
1388
1389 (void) suspend(0);
1390 break;
1391 }
1392 }
1393}
1394
1395static void apm_event_handler(void)
1396{
1397 static int pending_count = 4;
1398 int err;
1399
1400 if ((standbys_pending > 0) || (suspends_pending > 0)) {
1401 if ((apm_info.connection_version > 0x100) &&
1402 (pending_count-- <= 0)) {
1403 pending_count = 4;
1404 if (debug)
1405 printk(KERN_DEBUG "apm: setting state busy\n");
1406 err = set_system_power_state(APM_STATE_BUSY);
1407 if (err)
1408 apm_error("busy", err);
1409 }
1410 } else
1411 pending_count = 4;
1412 check_events();
1413}
1414
1415
1416
1417
1418
1419static void apm_mainloop(void)
1420{
1421 DECLARE_WAITQUEUE(wait, current);
1422
1423 add_wait_queue(&apm_waitqueue, &wait);
1424 set_current_state(TASK_INTERRUPTIBLE);
1425 for (;;) {
1426 schedule_timeout(APM_CHECK_TIMEOUT);
1427 if (exit_kapmd)
1428 break;
1429
1430
1431
1432
1433 set_current_state(TASK_INTERRUPTIBLE);
1434 apm_event_handler();
1435 }
1436 remove_wait_queue(&apm_waitqueue, &wait);
1437}
1438
1439static int check_apm_user(struct apm_user *as, const char *func)
1440{
1441 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
1442 printk(KERN_ERR "apm: %s passed bad filp\n", func);
1443 return 1;
1444 }
1445 return 0;
1446}
1447
1448static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
1449{
1450 struct apm_user * as;
1451 int i;
1452 apm_event_t event;
1453
1454 as = fp->private_data;
1455 if (check_apm_user(as, "read"))
1456 return -EIO;
1457 if ((int)count < sizeof(apm_event_t))
1458 return -EINVAL;
1459 if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
1460 return -EAGAIN;
1461 wait_event_interruptible(apm_waitqueue, !queue_empty(as));
1462 i = count;
1463 while ((i >= sizeof(event)) && !queue_empty(as)) {
1464 event = get_queued_event(as);
1465 if (copy_to_user(buf, &event, sizeof(event))) {
1466 if (i < count)
1467 break;
1468 return -EFAULT;
1469 }
1470 switch (event) {
1471 case APM_SYS_SUSPEND:
1472 case APM_USER_SUSPEND:
1473 as->suspends_read++;
1474 break;
1475
1476 case APM_SYS_STANDBY:
1477 case APM_USER_STANDBY:
1478 as->standbys_read++;
1479 break;
1480 }
1481 buf += sizeof(event);
1482 i -= sizeof(event);
1483 }
1484 if (i < count)
1485 return count - i;
1486 if (signal_pending(current))
1487 return -ERESTARTSYS;
1488 return 0;
1489}
1490
1491static unsigned int do_poll(struct file *fp, poll_table * wait)
1492{
1493 struct apm_user * as;
1494
1495 as = fp->private_data;
1496 if (check_apm_user(as, "poll"))
1497 return 0;
1498 poll_wait(fp, &apm_waitqueue, wait);
1499 if (!queue_empty(as))
1500 return POLLIN | POLLRDNORM;
1501 return 0;
1502}
1503
1504static int do_ioctl(struct inode * inode, struct file *filp,
1505 u_int cmd, u_long arg)
1506{
1507 struct apm_user * as;
1508
1509 as = filp->private_data;
1510 if (check_apm_user(as, "ioctl"))
1511 return -EIO;
1512 if ((!as->suser) || (!as->writer))
1513 return -EPERM;
1514 switch (cmd) {
1515 case APM_IOC_STANDBY:
1516 if (as->standbys_read > 0) {
1517 as->standbys_read--;
1518 as->standbys_pending--;
1519 standbys_pending--;
1520 } else
1521 queue_event(APM_USER_STANDBY, as);
1522 if (standbys_pending <= 0)
1523 standby();
1524 break;
1525 case APM_IOC_SUSPEND:
1526 if (as->suspends_read > 0) {
1527 as->suspends_read--;
1528 as->suspends_pending--;
1529 suspends_pending--;
1530 } else
1531 queue_event(APM_USER_SUSPEND, as);
1532 if (suspends_pending <= 0) {
1533 return suspend(1);
1534 } else {
1535 as->suspend_wait = 1;
1536 wait_event_interruptible(apm_suspend_waitqueue,
1537 as->suspend_wait == 0);
1538 return as->suspend_result;
1539 }
1540 break;
1541 default:
1542 return -EINVAL;
1543 }
1544 return 0;
1545}
1546
1547static int do_release(struct inode * inode, struct file * filp)
1548{
1549 struct apm_user * as;
1550
1551 as = filp->private_data;
1552 if (check_apm_user(as, "release"))
1553 return 0;
1554 filp->private_data = NULL;
1555 lock_kernel();
1556 if (as->standbys_pending > 0) {
1557 standbys_pending -= as->standbys_pending;
1558 if (standbys_pending <= 0)
1559 standby();
1560 }
1561 if (as->suspends_pending > 0) {
1562 suspends_pending -= as->suspends_pending;
1563 if (suspends_pending <= 0)
1564 (void) suspend(1);
1565 }
1566 if (user_list == as)
1567 user_list = as->next;
1568 else {
1569 struct apm_user * as1;
1570
1571 for (as1 = user_list;
1572 (as1 != NULL) && (as1->next != as);
1573 as1 = as1->next)
1574 ;
1575 if (as1 == NULL)
1576 printk(KERN_ERR "apm: filp not in user list\n");
1577 else
1578 as1->next = as->next;
1579 }
1580 unlock_kernel();
1581 kfree(as);
1582 return 0;
1583}
1584
1585static int do_open(struct inode * inode, struct file * filp)
1586{
1587 struct apm_user * as;
1588
1589 as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
1590 if (as == NULL) {
1591 printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
1592 sizeof(*as));
1593 return -ENOMEM;
1594 }
1595 as->magic = APM_BIOS_MAGIC;
1596 as->event_tail = as->event_head = 0;
1597 as->suspends_pending = as->standbys_pending = 0;
1598 as->suspends_read = as->standbys_read = 0;
1599
1600
1601
1602
1603
1604
1605
1606 as->suser = capable(CAP_SYS_ADMIN);
1607 as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
1608 as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
1609 as->next = user_list;
1610 user_list = as;
1611 filp->private_data = as;
1612 return 0;
1613}
1614
1615static int apm_get_info(char *buf, char **start, off_t fpos, int length)
1616{
1617 char * p;
1618 unsigned short bx;
1619 unsigned short cx;
1620 unsigned short dx;
1621 int error;
1622 unsigned short ac_line_status = 0xff;
1623 unsigned short battery_status = 0xff;
1624 unsigned short battery_flag = 0xff;
1625 int percentage = -1;
1626 int time_units = -1;
1627 char *units = "?";
1628
1629 p = buf;
1630
1631 if ((smp_num_cpus == 1 || smp) &&
1632 !(error = apm_get_power_status(&bx, &cx, &dx))) {
1633 ac_line_status = (bx >> 8) & 0xff;
1634 battery_status = bx & 0xff;
1635 if ((cx & 0xff) != 0xff)
1636 percentage = cx & 0xff;
1637
1638 if (apm_info.connection_version > 0x100) {
1639 battery_flag = (cx >> 8) & 0xff;
1640 if (dx != 0xffff) {
1641 units = (dx & 0x8000) ? "min" : "sec";
1642 time_units = dx & 0x7fff;
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
1683
1684 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
1685 driver_version,
1686 (apm_info.bios.version >> 8) & 0xff,
1687 apm_info.bios.version & 0xff,
1688 apm_info.bios.flags,
1689 ac_line_status,
1690 battery_status,
1691 battery_flag,
1692 percentage,
1693 time_units,
1694 units);
1695
1696 return p - buf;
1697}
1698
1699static int apm(void *unused)
1700{
1701 unsigned short bx;
1702 unsigned short cx;
1703 unsigned short dx;
1704 int error;
1705 char * power_stat;
1706 char * bat_stat;
1707
1708 kapmd_running = 1;
1709
1710 daemonize();
1711
1712 strcpy(current->comm, "kapmd");
1713 sigfillset(¤t->blocked);
1714
1715#ifdef CONFIG_SMP
1716
1717
1718
1719
1720
1721
1722 if (cpu_number_map(smp_processor_id()) != 0) {
1723 current->cpus_allowed = 1;
1724 schedule();
1725 if (unlikely(cpu_number_map(smp_processor_id()) != 0))
1726 BUG();
1727 }
1728#endif
1729
1730 if (apm_info.connection_version == 0) {
1731 apm_info.connection_version = apm_info.bios.version;
1732 if (apm_info.connection_version > 0x100) {
1733
1734
1735
1736 if (apm_info.connection_version > 0x0102)
1737 apm_info.connection_version = 0x0102;
1738 error = apm_driver_version(&apm_info.connection_version);
1739 if (error != APM_SUCCESS) {
1740 apm_error("driver version", error);
1741
1742 apm_info.connection_version = 0x100;
1743 }
1744 }
1745 }
1746
1747 if (debug)
1748 printk(KERN_INFO "apm: Connection version %d.%d\n",
1749 (apm_info.connection_version >> 8) & 0xff,
1750 apm_info.connection_version & 0xff);
1751
1752#ifdef CONFIG_APM_DO_ENABLE
1753 if (apm_info.bios.flags & APM_BIOS_DISABLED) {
1754
1755
1756
1757
1758
1759 error = apm_enable_power_management(1);
1760 if (error) {
1761 apm_error("enable power management", error);
1762 return -1;
1763 }
1764 }
1765#endif
1766
1767 if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
1768 && (apm_info.connection_version > 0x0100)) {
1769 error = apm_engage_power_management(APM_DEVICE_ALL, 1);
1770 if (error) {
1771 apm_error("engage power management", error);
1772 return -1;
1773 }
1774 }
1775
1776 if (debug && (smp_num_cpus == 1 || smp )) {
1777 error = apm_get_power_status(&bx, &cx, &dx);
1778 if (error)
1779 printk(KERN_INFO "apm: power status not available\n");
1780 else {
1781 switch ((bx >> 8) & 0xff) {
1782 case 0: power_stat = "off line"; break;
1783 case 1: power_stat = "on line"; break;
1784 case 2: power_stat = "on backup power"; break;
1785 default: power_stat = "unknown"; break;
1786 }
1787 switch (bx & 0xff) {
1788 case 0: bat_stat = "high"; break;
1789 case 1: bat_stat = "low"; break;
1790 case 2: bat_stat = "critical"; break;
1791 case 3: bat_stat = "charging"; break;
1792 default: bat_stat = "unknown"; break;
1793 }
1794 printk(KERN_INFO
1795 "apm: AC %s, battery status %s, battery life ",
1796 power_stat, bat_stat);
1797 if ((cx & 0xff) == 0xff)
1798 printk("unknown\n");
1799 else
1800 printk("%d%%\n", cx & 0xff);
1801 if (apm_info.connection_version > 0x100) {
1802 printk(KERN_INFO
1803 "apm: battery flag 0x%02x, battery life ",
1804 (cx >> 8) & 0xff);
1805 if (dx == 0xffff)
1806 printk("unknown\n");
1807 else
1808 printk("%d %s\n", dx & 0x7fff,
1809 (dx & 0x8000) ?
1810 "minutes" : "seconds");
1811 }
1812 }
1813 }
1814
1815
1816 if (power_off)
1817 pm_power_off = apm_power_off;
1818 register_sysrq_key('o', &sysrq_poweroff_op);
1819
1820 if (smp_num_cpus == 1 || smp) {
1821#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1822 console_blank_hook = apm_console_blank;
1823#endif
1824 apm_mainloop();
1825#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
1826 console_blank_hook = NULL;
1827#endif
1828 }
1829 kapmd_running = 0;
1830
1831 return 0;
1832}
1833
1834#ifndef MODULE
1835static int __init apm_setup(char *str)
1836{
1837 int invert;
1838
1839 while ((str != NULL) && (*str != '\0')) {
1840 if (strncmp(str, "off", 3) == 0)
1841 apm_disabled = 1;
1842 if (strncmp(str, "on", 2) == 0)
1843 apm_disabled = 0;
1844 if ((strncmp(str, "bounce-interval=", 16) == 0) ||
1845 (strncmp(str, "bounce_interval=", 16) == 0))
1846 bounce_interval = simple_strtol(str + 16, NULL, 0);
1847 if ((strncmp(str, "idle-threshold=", 15) == 0) ||
1848 (strncmp(str, "idle_threshold=", 15) == 0))
1849 idle_threshold = simple_strtol(str + 15, NULL, 0);
1850 if ((strncmp(str, "idle-period=", 12) == 0) ||
1851 (strncmp(str, "idle_period=", 12) == 0))
1852 idle_period = simple_strtol(str + 12, NULL, 0);
1853 invert = (strncmp(str, "no-", 3) == 0) ||
1854 (strncmp(str, "no_", 3) == 0);
1855 if (invert)
1856 str += 3;
1857 if (strncmp(str, "debug", 5) == 0)
1858 debug = !invert;
1859 if (strncmp(str, "smp", 3) == 0)
1860 {
1861 smp = !invert;
1862 idle_threshold = 100;
1863 }
1864 if ((strncmp(str, "power-off", 9) == 0) ||
1865 (strncmp(str, "power_off", 9) == 0))
1866 power_off = !invert;
1867 if ((strncmp(str, "allow-ints", 10) == 0) ||
1868 (strncmp(str, "allow_ints", 10) == 0))
1869 apm_info.allow_ints = !invert;
1870 if ((strncmp(str, "broken-psr", 10) == 0) ||
1871 (strncmp(str, "broken_psr", 10) == 0))
1872 apm_info.get_power_status_broken = !invert;
1873 if ((strncmp(str, "realmode-power-off", 18) == 0) ||
1874 (strncmp(str, "realmode_power_off", 18) == 0))
1875 apm_info.realmode_power_off = !invert;
1876 str = strchr(str, ',');
1877 if (str != NULL)
1878 str += strspn(str, ", \t");
1879 }
1880 return 1;
1881}
1882
1883__setup("apm=", apm_setup);
1884#endif
1885
1886static struct file_operations apm_bios_fops = {
1887 owner: THIS_MODULE,
1888 read: do_read,
1889 poll: do_poll,
1890 ioctl: do_ioctl,
1891 open: do_open,
1892 release: do_release,
1893};
1894
1895static struct miscdevice apm_device = {
1896 APM_MINOR_DEV,
1897 "apm_bios",
1898 &apm_bios_fops
1899};
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911static int __init apm_init(void)
1912{
1913 struct proc_dir_entry *apm_proc;
1914
1915 if (apm_info.bios.version == 0) {
1916 printk(KERN_INFO "apm: BIOS not found.\n");
1917 return -ENODEV;
1918 }
1919 printk(KERN_INFO
1920 "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
1921 ((apm_info.bios.version >> 8) & 0xff),
1922 (apm_info.bios.version & 0xff),
1923 apm_info.bios.flags,
1924 driver_version);
1925 if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
1926 printk(KERN_INFO "apm: no 32 bit BIOS support\n");
1927 return -ENODEV;
1928 }
1929
1930 if (allow_ints)
1931 apm_info.allow_ints = 1;
1932 if (broken_psr)
1933 apm_info.get_power_status_broken = 1;
1934 if (realmode_power_off)
1935 apm_info.realmode_power_off = 1;
1936
1937 if (apm_disabled != -1)
1938 apm_info.disabled = apm_disabled;
1939
1940
1941
1942
1943
1944 if (apm_info.bios.version == 0x001)
1945 apm_info.bios.version = 0x100;
1946
1947
1948 if (apm_info.bios.version < 0x102)
1949 apm_info.bios.cseg_16_len = 0;
1950
1951 if (debug) {
1952 printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
1953 apm_info.bios.cseg, apm_info.bios.offset,
1954 apm_info.bios.cseg_16, apm_info.bios.dseg);
1955 if (apm_info.bios.version > 0x100)
1956 printk(" cseg len %x, dseg len %x",
1957 apm_info.bios.cseg_len,
1958 apm_info.bios.dseg_len);
1959 if (apm_info.bios.version > 0x101)
1960 printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
1961 printk("\n");
1962 }
1963
1964 if (apm_info.disabled) {
1965 printk(KERN_NOTICE "apm: disabled on user request.\n");
1966 return -ENODEV;
1967 }
1968 if ((smp_num_cpus > 1) && !power_off && !smp) {
1969 printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
1970 return -ENODEV;
1971 }
1972 if (PM_IS_ACTIVE()) {
1973 printk(KERN_NOTICE "apm: overridden by ACPI.\n");
1974 return -ENODEV;
1975 }
1976 pm_active = 1;
1977
1978
1979
1980
1981
1982
1983
1984 set_base(gdt[APM_40 >> 3],
1985 __va((unsigned long)0x40 << 4));
1986 _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
1987
1988 apm_bios_entry.offset = apm_info.bios.offset;
1989 apm_bios_entry.segment = APM_CS;
1990 set_base(gdt[APM_CS >> 3],
1991 __va((unsigned long)apm_info.bios.cseg << 4));
1992 set_base(gdt[APM_CS_16 >> 3],
1993 __va((unsigned long)apm_info.bios.cseg_16 << 4));
1994 set_base(gdt[APM_DS >> 3],
1995 __va((unsigned long)apm_info.bios.dseg << 4));
1996#ifndef APM_RELAX_SEGMENTS
1997 if (apm_info.bios.version == 0x100) {
1998#endif
1999
2000 _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
2001
2002 _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
2003
2004 _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
2005#ifndef APM_RELAX_SEGMENTS
2006 } else {
2007 _set_limit((char *)&gdt[APM_CS >> 3],
2008 (apm_info.bios.cseg_len - 1) & 0xffff);
2009 _set_limit((char *)&gdt[APM_CS_16 >> 3],
2010 (apm_info.bios.cseg_16_len - 1) & 0xffff);
2011 _set_limit((char *)&gdt[APM_DS >> 3],
2012 (apm_info.bios.dseg_len - 1) & 0xffff);
2013 }
2014#endif
2015
2016 apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
2017 if (apm_proc)
2018 SET_MODULE_OWNER(apm_proc);
2019
2020 kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
2021
2022 if (smp_num_cpus > 1 && !smp) {
2023 printk(KERN_NOTICE
2024 "apm: disabled - APM is not SMP safe (power off active).\n");
2025 return 0;
2026 }
2027
2028 misc_register(&apm_device);
2029
2030 if (HZ != 100)
2031 idle_period = (idle_period * HZ) / 100;
2032 if (idle_threshold < 100) {
2033 original_pm_idle = pm_idle;
2034 pm_idle = apm_cpu_idle;
2035 set_pm_idle = 1;
2036 }
2037
2038 return 0;
2039}
2040
2041static void __exit apm_exit(void)
2042{
2043 int error;
2044
2045 if (set_pm_idle)
2046 pm_idle = original_pm_idle;
2047 if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
2048 && (apm_info.connection_version > 0x0100)) {
2049 error = apm_engage_power_management(APM_DEVICE_ALL, 0);
2050 if (error)
2051 apm_error("disengage power management", error);
2052 }
2053 misc_deregister(&apm_device);
2054 remove_proc_entry("apm", NULL);
2055 unregister_sysrq_key('o',&sysrq_poweroff_op);
2056 if (power_off)
2057 pm_power_off = NULL;
2058 exit_kapmd = 1;
2059 while (kapmd_running)
2060 schedule();
2061 pm_active = 0;
2062}
2063
2064module_init(apm_init);
2065module_exit(apm_exit);
2066
2067MODULE_AUTHOR("Stephen Rothwell");
2068MODULE_DESCRIPTION("Advanced Power Management");
2069MODULE_LICENSE("GPL");
2070MODULE_PARM(debug, "i");
2071MODULE_PARM_DESC(debug, "Enable debug mode");
2072MODULE_PARM(power_off, "i");
2073MODULE_PARM_DESC(power_off, "Enable power off");
2074MODULE_PARM(bounce_interval, "i");
2075MODULE_PARM_DESC(bounce_interval,
2076 "Set the number of ticks to ignore suspend bounces");
2077MODULE_PARM(allow_ints, "i");
2078MODULE_PARM_DESC(allow_ints, "Allow interrupts during BIOS calls");
2079MODULE_PARM(broken_psr, "i");
2080MODULE_PARM_DESC(broken_psr, "BIOS has a broken GetPowerStatus call");
2081MODULE_PARM(realmode_power_off, "i");
2082MODULE_PARM_DESC(realmode_power_off,
2083 "Switch to real mode before powering off");
2084MODULE_PARM(idle_threshold, "i");
2085MODULE_PARM_DESC(idle_threshold,
2086 "System idle percentage above which to make APM BIOS idle calls");
2087MODULE_PARM(idle_period, "i");
2088MODULE_PARM_DESC(idle_period,
2089 "Period (in sec/100) over which to caculate the idle percentage");
2090MODULE_PARM(smp, "i");
2091MODULE_PARM_DESC(smp,
2092 "Set this to enable APM use on an SMP platform. Use with caution on older systems");
2093
2094EXPORT_NO_SYMBOLS;
2095