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