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