This source file includes following definitions.
- apm_driver_version
- apm_get_event
- apm_set_power_state
- apm_set_display_power_state
- apm_enable_power_management
- apm_get_power_status
- apm_engage_power_management
- apm_error
- apm_display_blank
- apm_display_unblank
- apm_register_callback
- apm_unregister_callback
- queue_empty
- get_queued_event
- queue_event
- set_time
- suspend
- standby
- get_event
- send_event
- check_events
- do_apm_timer
- apm_do_idle
- apm_do_busy
- check_apm_bios_struct
- do_read
- do_select
- do_ioctl
- do_release
- do_open
- apm_proc
- apm_setup
- apm_bios_init
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 #include <linux/config.h>
42 #include <linux/module.h>
43
44 #include <asm/system.h>
45 #include <asm/segment.h>
46
47 #include <linux/types.h>
48 #include <linux/stddef.h>
49 #include <linux/timer.h>
50 #include <linux/fcntl.h>
51 #include <linux/malloc.h>
52 #include <linux/linkage.h>
53 #include <linux/apm_bios.h>
54
55 static struct symbol_table apm_syms = {
56 #include <linux/symtab_begin.h>
57 X(apm_register_callback),
58 X(apm_unregister_callback),
59 #include <linux/symtab_end.h>
60 };
61
62 extern unsigned long get_cmos_time(void);
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 #undef APM_DEBUG
120
121
122
123
124
125 #define ALWAYS_CALL_BUSY
126
127
128
129
130
131 #define APM_NOINTS
132
133
134
135
136
137
138 #define APM_ZERO_SEGS
139
140
141
142
143
144
145
146
147
148
149 #define APM_RELAX_SEGMENTS
150
151
152
153
154 #define APM_CHECK_TIMEOUT (HZ)
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 #ifdef APM_NOINTS
170 # define APM_DO_CLI "cli\n\t"
171 #else
172 # define APM_DO_CLI
173 #endif
174 #ifdef APM_ZERO_SEGS
175 # define APM_DO_ZERO_SEGS \
176 "pushl %%ds\n\t" \
177 "pushl %%es\n\t" \
178 "pushl %%fs\n\t" \
179 "pushl %%gs\n\t" \
180 "xorl %%edx, %%edx\n\t" \
181 "mov %%dx, %%ds\n\t" \
182 "mov %%dx, %%es\n\t" \
183 "mov %%dx, %%fs\n\t" \
184 "mov %%dx, %%gs\n\t"
185 # define APM_DO_RESTORE_SEGS \
186 "popl %%gs\n\t" \
187 "popl %%fs\n\t" \
188 "popl %%es\n\t" \
189 "popl %%ds\n\t"
190 #else
191 # define APM_DO_ZERO_SEGS
192 # define APM_DO_RESTORE_SEGS
193 #endif
194
195 #define APM_BIOS_CALL(error_reg) \
196 __asm__ __volatile__( \
197 APM_DO_ZERO_SEGS \
198 "pushfl\n\t" \
199 APM_DO_CLI \
200 "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \
201 "setc %%" # error_reg "\n\t" \
202 "popfl\n\t" \
203 APM_DO_RESTORE_SEGS
204 #define APM_BIOS_CALL_END \
205 : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")
206
207 #ifdef CONFIG_APM_CPU_IDLE
208 #define APM_SET_CPU_IDLE(error) \
209 APM_BIOS_CALL(al) \
210 : "=a" (error) \
211 : "a" (0x5305) \
212 APM_BIOS_CALL_END
213 #endif
214
215 #define APM_SET_CPU_BUSY(error) \
216 APM_BIOS_CALL(al) \
217 : "=a" (error) \
218 : "a" (0x5306) \
219 APM_BIOS_CALL_END
220
221 #define APM_SET_POWER_STATE(state, error) \
222 APM_BIOS_CALL(al) \
223 : "=a" (error) \
224 : "a" (0x5307), "b" (0x0001), "c" (state) \
225 APM_BIOS_CALL_END
226
227 #ifdef CONFIG_APM_DISPLAY_BLANK
228 #define APM_SET_DISPLAY_POWER_STATE(state, error) \
229 APM_BIOS_CALL(al) \
230 : "=a" (error) \
231 : "a" (0x5307), "b" (0x01ff), "c" (state) \
232 APM_BIOS_CALL_END
233 #endif
234
235 #ifdef CONFIG_APM_DO_ENABLE
236 #define APM_ENABLE_POWER_MANAGEMENT(device, error) \
237 APM_BIOS_CALL(al) \
238 : "=a" (error) \
239 : "a" (0x5308), "b" (device), "c" (1) \
240 APM_BIOS_CALL_END
241 #endif
242
243 #define APM_GET_POWER_STATUS(bx, cx, dx, error) \
244 APM_BIOS_CALL(al) \
245 : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
246 : "a" (0x530a), "b" (1) \
247 APM_BIOS_CALL_END
248
249 #define APM_GET_EVENT(event, error) \
250 APM_BIOS_CALL(al) \
251 : "=a" (error), "=b" (event) \
252 : "a" (0x530b) \
253 APM_BIOS_CALL_END
254
255 #define APM_DRIVER_VERSION(ver, ax, error) \
256 APM_BIOS_CALL(bl) \
257 : "=a" (ax), "=b" (error) \
258 : "a" (0x530e), "b" (0), "c" (ver) \
259 APM_BIOS_CALL_END
260
261 #define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
262 APM_BIOS_CALL(al) \
263 : "=a" (error) \
264 : "a" (0x530f), "b" (device), "c" (1) \
265 APM_BIOS_CALL_END
266
267
268
269
270 static void suspend(void);
271 static void standby(void);
272 static void set_time(void);
273
274 static void check_events(void);
275 static void do_apm_timer(unsigned long);
276
277 static int do_open(struct inode *, struct file *);
278 static void do_release(struct inode *, struct file *);
279 static int do_read(struct inode *, struct file *, char *, int);
280 static int do_select(struct inode *, struct file *, int,
281 select_table *);
282 static int do_ioctl(struct inode *, struct file *, u_int, u_long);
283
284 extern int apm_register_callback(int (*)(apm_event_t));
285 extern void apm_unregister_callback(int (*)(apm_event_t));
286
287
288
289
290 static asmlinkage struct {
291 unsigned long offset;
292 unsigned short segment;
293 } apm_bios_entry;
294 static int apm_enabled = 0;
295 #ifdef CONFIG_APM_CPU_IDLE
296 static int clock_slowed = 0;
297 #endif
298 static int apm_major;
299 static int suspends_pending = 0;
300 static int standbys_pending = 0;
301
302 static long clock_cmos_diff;
303 static int got_clock_diff = 0;
304
305 static struct wait_queue * process_list = NULL;
306 static struct apm_bios_struct * user_list = NULL;
307
308 static struct timer_list apm_timer;
309
310 static char driver_version[] = "0.8";
311
312 #ifdef APM_DEBUG
313 static char * apm_event_name[] = {
314 "system standby",
315 "system suspend",
316 "normal resume",
317 "critical resume",
318 "low battery",
319 "power status change",
320 "update time",
321 "critical suspend",
322 "user standby",
323 "user suspend",
324 "system standby resume"
325 };
326 #define NR_APM_EVENT_NAME \
327 (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
328 #endif
329
330 static struct file_operations apm_bios_fops = {
331 NULL,
332 do_read,
333 NULL,
334 NULL,
335 do_select,
336 do_ioctl,
337 NULL,
338 do_open,
339 do_release,
340 NULL,
341 NULL
342 };
343
344 typedef struct callback_list_t {
345 int (* callback)(apm_event_t);
346 struct callback_list_t * next;
347 } callback_list_t;
348
349 static callback_list_t * callback_list = NULL;
350
351 typedef struct lookup_t {
352 int key;
353 char * msg;
354 } lookup_t;
355
356 static const lookup_t error_table[] = {
357
358 { APM_DISABLED, "Power management disabled" },
359 { APM_CONNECTED, "Real mode interface already connected" },
360 { APM_NOT_CONNECTED, "Interface not connected" },
361 { APM_16_CONNECTED, "16 bit interface already connected" },
362
363 { APM_32_CONNECTED, "32 bit interface already connected" },
364 { APM_32_UNSUPPORTED, "32 bit interface not supported" },
365 { APM_BAD_DEVICE, "Unrecognized device ID" },
366 { APM_BAD_PARAM, "Parameter out of range" },
367 { APM_NOT_ENGAGED, "Interface not engaged" },
368 { APM_BAD_STATE, "Unable to enter requested state" },
369
370 { APM_NOT_PRESENT, "No APM present" }
371 };
372 #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
373
374 static int apm_driver_version(u_short *val)
375 {
376 u_short error;
377
378 APM_DRIVER_VERSION(*val, *val, error);
379
380 if (error & 0xff)
381 return (*val >> 8);
382 return APM_SUCCESS;
383 }
384
385 static int apm_get_event(apm_event_t *event)
386 {
387 u_short error;
388
389 APM_GET_EVENT(*event, error);
390 if (error & 0xff)
391 return (error >> 8);
392 return APM_SUCCESS;
393 }
394
395 static int apm_set_power_state(u_short state)
396 {
397 u_short error;
398
399 APM_SET_POWER_STATE(state, error);
400 if (error & 0xff)
401 return (error >> 8);
402 return APM_SUCCESS;
403 }
404
405 #ifdef CONFIG_APM_DISPLAY_BLANK
406 static int apm_set_display_power_state(u_short state)
407 {
408 u_short error;
409
410 APM_SET_DISPLAY_POWER_STATE(state, error);
411 if (error & 0xff)
412 return (error >> 8);
413 return APM_SUCCESS;
414 }
415 #endif
416
417 #ifdef CONFIG_APM_DO_ENABLE
418 static int apm_enable_power_management(void)
419 {
420 u_short error;
421
422 APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100)
423 ? 0x0001 : 0xffff,
424 error);
425 if (error & 0xff)
426 return (error >> 8);
427 return APM_SUCCESS;
428 }
429 #endif
430
431 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
432 {
433 u_short error;
434
435 APM_GET_POWER_STATUS(*status, *bat, *life, error);
436 if (error & 0xff)
437 return (error >> 8);
438 return APM_SUCCESS;
439 }
440
441 static int apm_engage_power_management(u_short device)
442 {
443 u_short error;
444
445 APM_ENGAGE_POWER_MANAGEMENT(device, error);
446 if (error & 0xff)
447 return (error >> 8);
448 return APM_SUCCESS;
449 }
450
451 static void apm_error(char *str, int err)
452 {
453 int i;
454
455 for (i = 0; i < ERROR_COUNT; i++)
456 if (error_table[i].key == err) break;
457 if (i < ERROR_COUNT)
458 printk("apm_bios: %s: %s\n", str, error_table[i].msg);
459 else
460 printk("apm_bios: %s: unknown error code %#2.2x\n", str, err);
461 }
462
463 int apm_display_blank(void)
464 {
465 #ifdef CONFIG_APM_DISPLAY_BLANK
466 int error;
467
468 if (apm_bios_info.version == 0)
469 return 0;
470 error = apm_set_display_power_state(APM_STATE_STANDBY);
471 if (error == APM_SUCCESS)
472 return 1;
473 apm_error("set display standby", error);
474 #endif
475 return 0;
476 }
477
478 int apm_display_unblank(void)
479 {
480 #ifdef CONFIG_APM_DISPLAY_BLANK
481 int error;
482
483 if (apm_bios_info.version == 0)
484 return 0;
485 error = apm_set_display_power_state(APM_STATE_READY);
486 if (error == APM_SUCCESS)
487 return 1;
488 apm_error("set display ready", error);
489 #endif
490 return 0;
491 }
492
493 int apm_register_callback(int (*callback)(apm_event_t))
494 {
495 callback_list_t * new;
496
497 new = kmalloc(sizeof(callback_list_t), GFP_KERNEL);
498 if (new == NULL)
499 return -ENOMEM;
500 new->callback = callback;
501 new->next = callback_list;
502 callback_list = new;
503 return 0;
504 }
505
506 void apm_unregister_callback(int (*callback)(apm_event_t))
507 {
508 callback_list_t ** ptr;
509 callback_list_t * old;
510
511 ptr = &callback_list;
512 for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next)
513 if ((*ptr)->callback == callback)
514 break;
515 old = *ptr;
516 *ptr = old->next;
517 kfree_s(old, sizeof(callback_list_t));
518 }
519
520 static int queue_empty(struct apm_bios_struct * as)
521 {
522 return as->event_head == as->event_tail;
523 }
524
525 static apm_event_t get_queued_event(struct apm_bios_struct * as)
526 {
527 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
528 return as->events[as->event_tail];
529 }
530
531 static int queue_event(apm_event_t event)
532 {
533 struct apm_bios_struct * as;
534
535 if (user_list == NULL)
536 return 0;
537 for (as = user_list; as != NULL; as = as->next) {
538 as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
539 if (as->event_head == as->event_tail)
540 as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
541 as->events[as->event_head] = event;
542 if (!as->suser)
543 continue;
544 switch (event) {
545 case APM_SYS_SUSPEND:
546 case APM_USER_SUSPEND:
547 as->suspends_pending++;
548 suspends_pending++;
549 break;
550
551 case APM_SYS_STANDBY:
552 case APM_USER_STANDBY:
553 as->standbys_pending++;
554 standbys_pending++;
555 break;
556 }
557 }
558 wake_up_interruptible(&process_list);
559 return 1;
560 }
561
562 static void set_time(void)
563 {
564 unsigned long flags;
565
566 if (!got_clock_diff)
567 return;
568
569 save_flags(flags);
570 cli();
571 CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
572 restore_flags(flags);
573 }
574
575 static void suspend(void)
576 {
577 unsigned long flags;
578 int err;
579
580
581
582 save_flags(flags);
583 cli();
584 clock_cmos_diff = CURRENT_TIME - get_cmos_time();
585 got_clock_diff = 1;
586 restore_flags(flags);
587
588 err = apm_set_power_state(APM_STATE_SUSPEND);
589 if (err)
590 apm_error("suspend", err);
591 set_time();
592 }
593
594 static void standby(void)
595 {
596 int err;
597
598 err = apm_set_power_state(APM_STATE_STANDBY);
599 if (err)
600 apm_error("standby", err);
601 }
602
603 static apm_event_t get_event(void)
604 {
605 int error;
606 apm_event_t event;
607
608 static int notified = 0;
609
610 error = apm_get_event(&event);
611 if (error == APM_SUCCESS)
612 return event;
613
614 if ((error != APM_NO_EVENTS) && (notified++ == 0))
615 apm_error("get_event", error);
616
617 return 0;
618 }
619
620 static void send_event(apm_event_t event, apm_event_t undo)
621 {
622 callback_list_t * call;
623 callback_list_t * fix;
624
625 for (call = callback_list; call != NULL; call = call->next) {
626 if (call->callback(event) && undo) {
627 for (fix = callback_list; fix != call; fix = fix->next)
628 fix->callback(undo);
629 if (apm_bios_info.version > 0x100)
630 apm_set_power_state(APM_STATE_REJECT);
631 return;
632 }
633 }
634
635 queue_event(event);
636 }
637
638 static void check_events(void)
639 {
640 apm_event_t event;
641
642 while ((event = get_event()) != 0) {
643 switch (event) {
644 case APM_SYS_STANDBY:
645 case APM_USER_STANDBY:
646 send_event(event, APM_STANDBY_RESUME);
647 if (standbys_pending <= 0)
648 standby();
649 break;
650
651 case APM_USER_SUSPEND:
652 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
653 apm_set_power_state(APM_STATE_REJECT);
654 break;
655 #endif
656 case APM_SYS_SUSPEND:
657 send_event(event, APM_NORMAL_RESUME);
658 if (suspends_pending <= 0)
659 suspend();
660 break;
661
662 case APM_NORMAL_RESUME:
663 case APM_CRITICAL_RESUME:
664 case APM_STANDBY_RESUME:
665 set_time();
666 send_event(event, 0);
667 break;
668
669 case APM_LOW_BATTERY:
670 case APM_POWER_STATUS_CHANGE:
671 send_event(event, 0);
672 break;
673
674 case APM_UPDATE_TIME:
675 set_time();
676 break;
677
678 case APM_CRITICAL_SUSPEND:
679 suspend();
680 break;
681 }
682 #ifdef APM_DEBUG
683 if (event <= NR_APM_EVENT_NAME)
684 printk("APM BIOS received %s notify\n",
685 apm_event_name[event - 1]);
686 else
687 printk("APM BIOS received unknown event 0x%02x\n",
688 event);
689 #endif
690 }
691 }
692
693 static void do_apm_timer(unsigned long unused)
694 {
695 int err;
696
697 static int pending_count = 0;
698
699 if (((standbys_pending > 0) || (suspends_pending > 0))
700 && (apm_bios_info.version > 0x100)
701 && (pending_count-- <= 0)) {
702 pending_count = 4;
703
704 err = apm_set_power_state(APM_STATE_BUSY);
705 if (err)
706 apm_error("busy", err);
707 }
708
709 if (!(((standbys_pending > 0) || (suspends_pending > 0))
710 && (apm_bios_info.version == 0x100)))
711 check_events();
712
713 init_timer(&apm_timer);
714 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
715 add_timer(&apm_timer);
716 }
717
718 int apm_do_idle(void)
719 {
720 #ifdef CONFIG_APM_CPU_IDLE
721 unsigned short error;
722
723 if (!apm_enabled)
724 return 0;
725
726 APM_SET_CPU_IDLE(error);
727 if (error & 0xff)
728 return 0;
729
730 clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
731 return 1;
732 #else
733 return 0;
734 #endif
735 }
736
737 void apm_do_busy(void)
738 {
739 #ifdef CONFIG_APM_CPU_IDLE
740 unsigned short error;
741
742 #ifndef ALWAYS_CALL_BUSY
743 if (!clock_slowed)
744 return;
745 #endif
746
747 APM_SET_CPU_BUSY(error);
748
749 clock_slowed = 0;
750 #endif
751 }
752
753 static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
754 {
755 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
756 printk("apm_bios: %s passed bad filp", func);
757 return 1;
758 }
759 return 0;
760 }
761
762 static int do_read(struct inode *inode, struct file *fp, char *buf, int count)
763 {
764 struct apm_bios_struct * as;
765 int i;
766 apm_event_t event;
767 struct wait_queue wait = { current, NULL };
768
769 as = fp->private_data;
770 if (check_apm_bios_struct(as, "read"))
771 return -EIO;
772 if (count < sizeof(apm_event_t))
773 return -EINVAL;
774 if (queue_empty(as)) {
775 if (fp->f_flags & O_NONBLOCK)
776 return -EAGAIN;
777 add_wait_queue(&process_list, &wait);
778 repeat:
779 current->state = TASK_INTERRUPTIBLE;
780 if (queue_empty(as)
781 && !(current->signal & ~current->blocked)) {
782 schedule();
783 goto repeat;
784 }
785 current->state = TASK_RUNNING;
786 remove_wait_queue(&process_list, &wait);
787 }
788 i = count;
789 while ((i >= sizeof(event)) && !queue_empty(as)) {
790 event = get_queued_event(as);
791 memcpy_tofs(buf, &event, sizeof(event));
792 buf += sizeof(event);
793 i -= sizeof(event);
794 }
795 if (i < count)
796 return count - i;
797 if (current->signal & ~current->blocked)
798 return -ERESTARTSYS;
799 return 0;
800 }
801
802 static int do_select(struct inode *inode, struct file *fp, int sel_type,
803 select_table * wait)
804 {
805 struct apm_bios_struct * as;
806
807 as = fp->private_data;
808 if (check_apm_bios_struct(as, "select"))
809 return 0;
810 if (sel_type != SEL_IN)
811 return 0;
812 if (!queue_empty(as))
813 return 1;
814 select_wait(&process_list, wait);
815 return 0;
816 }
817
818 static int do_ioctl(struct inode * inode, struct file *filp,
819 u_int cmd, u_long arg)
820 {
821 struct apm_bios_struct * as;
822
823 as = filp->private_data;
824 if (check_apm_bios_struct(as, "ioctl"))
825 return -EIO;
826 switch (cmd) {
827 case APM_IOC_STANDBY:
828 if (as->standbys_pending > 0) {
829 as->standbys_pending--;
830 standbys_pending--;
831 if (standbys_pending <= 0)
832 standby();
833 }
834 break;
835 case APM_IOC_SUSPEND:
836 if (as->suspends_pending > 0) {
837 as->suspends_pending--;
838 suspends_pending--;
839 if (suspends_pending <= 0)
840 suspend();
841 }
842 break;
843 default:
844 return -EINVAL;
845 }
846 return 0;
847 }
848
849 static void do_release(struct inode * inode, struct file * filp)
850 {
851 struct apm_bios_struct * as;
852
853 as = filp->private_data;
854 filp->private_data = NULL;
855 if (check_apm_bios_struct(as, "release"))
856 return;
857 if (as->standbys_pending > 0) {
858 standbys_pending -= as->standbys_pending;
859 if (standbys_pending <= 0)
860 standby();
861 }
862 if (as->suspends_pending > 0) {
863 suspends_pending -= as->suspends_pending;
864 if (suspends_pending <= 0)
865 suspend();
866 }
867 if (user_list == as)
868 user_list = as->next;
869 else {
870 struct apm_bios_struct * as1;
871
872 for (as1 = user_list;
873 (as1 != NULL) && (as1->next != as);
874 as1 = as1->next)
875 ;
876 if (as1 == NULL)
877 printk("apm_bios: filp not in user list");
878 else
879 as1->next = as->next;
880 }
881 kfree_s(as, sizeof(*as));
882 }
883
884 static int do_open(struct inode * inode, struct file * filp)
885 {
886 struct apm_bios_struct * as;
887
888 as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
889 if (as == NULL) {
890 printk("apm_bios: cannot allocate struct of size %d bytes",
891 sizeof(*as));
892 return -ENOMEM;
893 }
894 as->magic = APM_BIOS_MAGIC;
895 as->event_tail = as->event_head = 0;
896 as->suspends_pending = as->standbys_pending = 0;
897 as->suser = suser();
898 as->next = user_list;
899 user_list = as;
900 filp->private_data = as;
901 return 0;
902 }
903
904 int apm_proc(char *buf)
905 {
906 char * p;
907 unsigned short bx;
908 unsigned short cx;
909 unsigned short dx;
910 unsigned short error;
911 unsigned short ac_line_status = 0xff;
912 unsigned short battery_status = 0xff;
913 unsigned short battery_flag = 0xff;
914 unsigned short percentage = -1;
915 int time_units = -1;
916 char *units = "?";
917
918 if (apm_bios_info.version == 0)
919 return 0;
920 p = buf;
921
922 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) != 0) {
923 if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
924 ac_line_status = (bx >> 8) & 0xff;
925 battery_status = bx & 0xff;
926 if ((cx & 0xff) != 0xff)
927 percentage = cx & 0xff;
928
929 if (apm_bios_info.version > 0x100) {
930 battery_flag = (cx >> 8) & 0xff;
931 if (dx != 0xffff) {
932 if ((dx & 0x8000) == 0x8000) {
933 units = "min";
934 time_units = dx & 0x7ffe;
935 } else {
936 units = "sec";
937 time_units = dx & 0x7fff;
938 }
939 }
940 }
941 }
942 }
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
981 driver_version,
982 (apm_bios_info.version >> 8) & 0xff,
983 apm_bios_info.version & 0xff,
984 apm_bios_info.flags,
985 ac_line_status,
986 battery_status,
987 battery_flag,
988 percentage,
989 time_units,
990 units );
991
992 return p - buf;
993 }
994
995 static int apm_setup(void)
996 {
997 unsigned short bx;
998 unsigned short cx;
999 unsigned short dx;
1000 unsigned short error;
1001 char * power_stat;
1002 char * bat_stat;
1003
1004 if (apm_bios_info.version == 0) {
1005 printk("APM BIOS not found.\n");
1006 return -1;
1007 }
1008 printk("APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
1009 ((apm_bios_info.version >> 8) & 0xff) + '0',
1010 (apm_bios_info.version & 0xff) + '0',
1011 apm_bios_info.flags,
1012 driver_version);
1013 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
1014 printk(" No 32 bit BIOS support\n");
1015 return -1;
1016 }
1017
1018
1019
1020
1021
1022 if (apm_bios_info.version == 0x001)
1023 apm_bios_info.version = 0x100;
1024
1025 printk(" Entry %x:%lx cseg16 %x dseg %x",
1026 apm_bios_info.cseg, apm_bios_info.offset,
1027 apm_bios_info.cseg_16, apm_bios_info.dseg);
1028 if (apm_bios_info.version > 0x100)
1029 printk(" cseg len %x, dseg len %x",
1030 apm_bios_info.cseg_len, apm_bios_info.dseg_len);
1031 printk("\n");
1032
1033 apm_bios_entry.offset = apm_bios_info.offset;
1034 apm_bios_entry.segment = APM_CS;
1035 set_base(gdt[APM_CS >> 3],
1036 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4));
1037 set_base(gdt[APM_CS_16 >> 3],
1038 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
1039 set_base(gdt[APM_DS >> 3],
1040 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4));
1041 if (apm_bios_info.version == 0x100) {
1042 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1043 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1044 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1045 } else {
1046 #ifdef APM_RELAX_SEGMENTS
1047
1048 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1049
1050 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1051
1052 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1053 #else
1054 set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
1055 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1056 set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
1057 #endif
1058 apm_bios_info.version = 0x0101;
1059 error = apm_driver_version(&apm_bios_info.version);
1060 if (error != 0)
1061 apm_bios_info.version = 0x100;
1062 else {
1063 apm_engage_power_management(0x0001);
1064 printk( " Connection version %d.%d\n",
1065 (apm_bios_info.version >> 8) & 0xff,
1066 apm_bios_info.version & 0xff );
1067 apm_bios_info.version = 0x0101;
1068 }
1069 }
1070
1071 error = apm_get_power_status(&bx, &cx, &dx);
1072 if (error)
1073 printk(" Power status not available\n");
1074 else {
1075 switch ((bx >> 8) & 0xff) {
1076 case 0: power_stat = "off line"; break;
1077 case 1: power_stat = "on line"; break;
1078 case 2: power_stat = "on backup power"; break;
1079 default: power_stat = "unknown"; break;
1080 }
1081 switch (bx & 0xff) {
1082 case 0: bat_stat = "high"; break;
1083 case 1: bat_stat = "low"; break;
1084 case 2: bat_stat = "critical"; break;
1085 case 3: bat_stat = "charging"; break;
1086 default: bat_stat = "unknown"; break;
1087 }
1088 printk(" AC %s, battery status %s, battery life ",
1089 power_stat, bat_stat);
1090 if ((cx & 0xff) == 0xff)
1091 printk("unknown\n");
1092 else
1093 printk("%d%%\n", cx & 0xff);
1094 if (apm_bios_info.version > 0x100) {
1095 printk(" battery flag 0x%02x, battery life ",
1096 (cx >> 8) & 0xff);
1097 if (dx == 0xffff)
1098 printk("unknown\n");
1099 else {
1100 if ((dx & 0x8000))
1101 printk("%d minutes\n", dx & 0x7ffe );
1102 else
1103 printk("%d seconds\n", dx & 0x7fff );
1104 }
1105 }
1106 }
1107
1108 #ifdef CONFIG_APM_DO_ENABLE
1109
1110
1111
1112
1113
1114 error = apm_enable_power_management();
1115 if (error)
1116 apm_error("enable power management", error);
1117 #endif
1118
1119 init_timer(&apm_timer);
1120 apm_timer.function = do_apm_timer;
1121 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
1122 add_timer(&apm_timer);
1123
1124 register_symtab(&apm_syms);
1125
1126 apm_enabled = 1;
1127
1128 if ((apm_major = register_chrdev(0, "apm_bios", &apm_bios_fops)) < 0)
1129 printk("APM BIOS: Cannot allocate major device number\n");
1130
1131 return 0;
1132 }
1133
1134 void apm_bios_init(void)
1135 {
1136 apm_setup();
1137 }