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