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 check_events();
709
710 init_timer(&apm_timer);
711 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
712 add_timer(&apm_timer);
713 }
714
715 int apm_do_idle(void)
716 {
717 #ifdef CONFIG_APM_CPU_IDLE
718 unsigned short error;
719
720 if (!apm_enabled)
721 return 0;
722
723 APM_SET_CPU_IDLE(error);
724 if (error & 0xff)
725 return 0;
726
727 clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
728 return 1;
729 #else
730 return 0;
731 #endif
732 }
733
734 void apm_do_busy(void)
735 {
736 #ifdef CONFIG_APM_CPU_IDLE
737 unsigned short error;
738
739 #ifndef ALWAYS_CALL_BUSY
740 if (!clock_slowed)
741 return;
742 #endif
743
744 APM_SET_CPU_BUSY(error);
745
746 clock_slowed = 0;
747 #endif
748 }
749
750 static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
751 {
752 if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
753 printk("apm_bios: %s passed bad filp", func);
754 return 1;
755 }
756 return 0;
757 }
758
759 static int do_read(struct inode *inode, struct file *fp, char *buf, int count)
760 {
761 struct apm_bios_struct * as;
762 int i;
763 apm_event_t event;
764 struct wait_queue wait = { current, NULL };
765
766 as = fp->private_data;
767 if (check_apm_bios_struct(as, "read"))
768 return -EIO;
769 if (count < sizeof(apm_event_t))
770 return -EINVAL;
771 if (queue_empty(as)) {
772 if (fp->f_flags & O_NONBLOCK)
773 return -EAGAIN;
774 add_wait_queue(&process_list, &wait);
775 repeat:
776 current->state = TASK_INTERRUPTIBLE;
777 if (queue_empty(as)
778 && !(current->signal & ~current->blocked)) {
779 schedule();
780 goto repeat;
781 }
782 current->state = TASK_RUNNING;
783 remove_wait_queue(&process_list, &wait);
784 }
785 i = count;
786 while ((i >= sizeof(event)) && !queue_empty(as)) {
787 event = get_queued_event(as);
788 memcpy_tofs(buf, &event, sizeof(event));
789 buf += sizeof(event);
790 i -= sizeof(event);
791 }
792 if (i < count)
793 return count - i;
794 if (current->signal & ~current->blocked)
795 return -ERESTARTSYS;
796 return 0;
797 }
798
799 static int do_select(struct inode *inode, struct file *fp, int sel_type,
800 select_table * wait)
801 {
802 struct apm_bios_struct * as;
803
804 as = fp->private_data;
805 if (check_apm_bios_struct(as, "select"))
806 return 0;
807 if (sel_type != SEL_IN)
808 return 0;
809 if (!queue_empty(as))
810 return 1;
811 select_wait(&process_list, wait);
812 return 0;
813 }
814
815 static int do_ioctl(struct inode * inode, struct file *filp,
816 u_int cmd, u_long arg)
817 {
818 struct apm_bios_struct * as;
819
820 as = filp->private_data;
821 if (check_apm_bios_struct(as, "ioctl"))
822 return -EIO;
823 switch (cmd) {
824 case APM_IOC_STANDBY:
825 if (as->standbys_pending > 0) {
826 as->standbys_pending--;
827 standbys_pending--;
828 if (standbys_pending <= 0)
829 standby();
830 }
831 break;
832 case APM_IOC_SUSPEND:
833 if (as->suspends_pending > 0) {
834 as->suspends_pending--;
835 suspends_pending--;
836 if (suspends_pending <= 0)
837 suspend();
838 }
839 break;
840 default:
841 return -EINVAL;
842 }
843 return 0;
844 }
845
846 static void do_release(struct inode * inode, struct file * filp)
847 {
848 struct apm_bios_struct * as;
849
850 as = filp->private_data;
851 filp->private_data = NULL;
852 if (check_apm_bios_struct(as, "release"))
853 return;
854 if (as->standbys_pending > 0) {
855 standbys_pending -= as->standbys_pending;
856 if (standbys_pending <= 0)
857 standby();
858 }
859 if (as->suspends_pending > 0) {
860 suspends_pending -= as->suspends_pending;
861 if (suspends_pending <= 0)
862 suspend();
863 }
864 if (user_list == as)
865 user_list = as->next;
866 else {
867 struct apm_bios_struct * as1;
868
869 for (as1 = user_list;
870 (as1 != NULL) && (as1->next != as);
871 as1 = as1->next)
872 ;
873 if (as1 == NULL)
874 printk("apm_bios: filp not in user list");
875 else
876 as1->next = as->next;
877 }
878 kfree_s(as, sizeof(*as));
879 }
880
881 static int do_open(struct inode * inode, struct file * filp)
882 {
883 struct apm_bios_struct * as;
884
885 as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
886 if (as == NULL) {
887 printk("apm_bios: cannot allocate struct of size %d bytes",
888 sizeof(*as));
889 return -ENOMEM;
890 }
891 as->magic = APM_BIOS_MAGIC;
892 as->event_tail = as->event_head = 0;
893 as->suspends_pending = as->standbys_pending = 0;
894 as->suser = suser();
895 as->next = user_list;
896 user_list = as;
897 filp->private_data = as;
898 return 0;
899 }
900
901 int apm_proc(char *buf)
902 {
903 char * p;
904 unsigned short bx;
905 unsigned short cx;
906 unsigned short dx;
907 unsigned short error;
908 unsigned short ac_line_status = 0xff;
909 unsigned short battery_status = 0xff;
910 unsigned short battery_flag = 0xff;
911 unsigned short percentage = -1;
912 int time_units = -1;
913 char *units = "?";
914
915 if (apm_bios_info.version == 0)
916 return 0;
917 p = buf;
918
919 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) != 0) {
920 if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
921 ac_line_status = (bx >> 8) & 0xff;
922 battery_status = bx & 0xff;
923 if ((cx & 0xff) != 0xff)
924 percentage = cx & 0xff;
925
926 if (apm_bios_info.version > 0x100) {
927 battery_flag = (cx >> 8) & 0xff;
928 if (dx != 0xffff) {
929 if ((dx & 0x8000) == 0x8000) {
930 units = "min";
931 time_units = dx & 0x7ffe;
932 } else {
933 units = "sec";
934 time_units = dx & 0x7fff;
935 }
936 }
937 }
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 p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
978 driver_version,
979 (apm_bios_info.version >> 8) & 0xff,
980 apm_bios_info.version & 0xff,
981 apm_bios_info.flags,
982 ac_line_status,
983 battery_status,
984 battery_flag,
985 percentage,
986 time_units,
987 units );
988
989 return p - buf;
990 }
991
992 static int apm_setup(void)
993 {
994 unsigned short bx;
995 unsigned short cx;
996 unsigned short dx;
997 unsigned short error;
998 char * power_stat;
999 char * bat_stat;
1000
1001 if (apm_bios_info.version == 0) {
1002 printk("APM BIOS not found.\n");
1003 return -1;
1004 }
1005 printk("APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
1006 ((apm_bios_info.version >> 8) & 0xff) + '0',
1007 (apm_bios_info.version & 0xff) + '0',
1008 apm_bios_info.flags,
1009 driver_version);
1010 if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
1011 printk(" No 32 bit BIOS support\n");
1012 return -1;
1013 }
1014
1015
1016
1017
1018
1019 if (apm_bios_info.version == 0x001)
1020 apm_bios_info.version = 0x100;
1021
1022 printk(" Entry %x:%lx cseg16 %x dseg %x",
1023 apm_bios_info.cseg, apm_bios_info.offset,
1024 apm_bios_info.cseg_16, apm_bios_info.dseg);
1025 if (apm_bios_info.version > 0x100)
1026 printk(" cseg len %x, dseg len %x",
1027 apm_bios_info.cseg_len, apm_bios_info.dseg_len);
1028 printk("\n");
1029
1030 apm_bios_entry.offset = apm_bios_info.offset;
1031 apm_bios_entry.segment = APM_CS;
1032 set_base(gdt[APM_CS >> 3],
1033 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4));
1034 set_base(gdt[APM_CS_16 >> 3],
1035 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
1036 set_base(gdt[APM_DS >> 3],
1037 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4));
1038 if (apm_bios_info.version == 0x100) {
1039 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1040 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1041 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1042 } else {
1043 #ifdef APM_RELAX_SEGMENTS
1044
1045 set_limit(gdt[APM_CS >> 3], 64 * 1024);
1046
1047 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1048
1049 set_limit(gdt[APM_DS >> 3], 64 * 1024);
1050 #else
1051 set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
1052 set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
1053 set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
1054 #endif
1055 apm_bios_info.version = 0x0101;
1056 error = apm_driver_version(&apm_bios_info.version);
1057 if (error != 0)
1058 apm_bios_info.version = 0x100;
1059 else {
1060 apm_engage_power_management(0x0001);
1061 printk( " Connection version %d.%d\n",
1062 (apm_bios_info.version >> 8) & 0xff,
1063 apm_bios_info.version & 0xff );
1064 apm_bios_info.version = 0x0101;
1065 }
1066 }
1067
1068 error = apm_get_power_status(&bx, &cx, &dx);
1069 if (error)
1070 printk(" Power status not available\n");
1071 else {
1072 switch ((bx >> 8) & 0xff) {
1073 case 0: power_stat = "off line"; break;
1074 case 1: power_stat = "on line"; break;
1075 case 2: power_stat = "on backup power"; break;
1076 default: power_stat = "unknown"; break;
1077 }
1078 switch (bx & 0xff) {
1079 case 0: bat_stat = "high"; break;
1080 case 1: bat_stat = "low"; break;
1081 case 2: bat_stat = "critical"; break;
1082 case 3: bat_stat = "charging"; break;
1083 default: bat_stat = "unknown"; break;
1084 }
1085 printk(" AC %s, battery status %s, battery life ",
1086 power_stat, bat_stat);
1087 if ((cx & 0xff) == 0xff)
1088 printk("unknown\n");
1089 else
1090 printk("%d%%\n", cx & 0xff);
1091 if (apm_bios_info.version > 0x100) {
1092 printk(" battery flag 0x%02x, battery life ",
1093 (cx >> 8) & 0xff);
1094 if (dx == 0xffff)
1095 printk("unknown\n");
1096 else {
1097 if ((dx & 0x8000))
1098 printk("%d minutes\n", dx & 0x7ffe );
1099 else
1100 printk("%d seconds\n", dx & 0x7fff );
1101 }
1102 }
1103 }
1104
1105 #ifdef CONFIG_APM_DO_ENABLE
1106
1107
1108
1109
1110
1111 error = apm_enable_power_management();
1112 if (error)
1113 apm_error("enable power management", error);
1114 #endif
1115
1116 init_timer(&apm_timer);
1117 apm_timer.function = do_apm_timer;
1118 apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
1119 add_timer(&apm_timer);
1120
1121 register_symtab(&apm_syms);
1122
1123 apm_enabled = 1;
1124
1125 if ((apm_major = register_chrdev(0, "apm_bios", &apm_bios_fops)) < 0)
1126 printk("APM BIOS: Cannot allocate major device number\n");
1127
1128 return 0;
1129 }
1130
1131 void apm_bios_init(void)
1132 {
1133 apm_setup();
1134 }