1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/config.h>
14#include <linux/module.h>
15
16#include <asm/system.h>
17#include <asm/segment.h>
18#include <asm/io.h>
19
20#include <linux/types.h>
21#include <linux/stddef.h>
22#include <linux/timer.h>
23#include <linux/fcntl.h>
24#include <linux/linkage.h>
25#include <linux/stat.h>
26#include <linux/proc_fs.h>
27#include <linux/miscdevice.h>
28#include <linux/list.h>
29#include <linux/ioport.h>
30#include <linux/poll.h>
31#include <linux/init.h>
32#include <linux/slab.h>
33
34#define __KERNEL_SYSCALLS__
35#include <asm/unistd.h>
36
37#include "h8.h"
38
39#define DEBUG_H8
40
41#ifdef DEBUG_H8
42#define Dprintk printk
43#else
44#define Dprintk
45#endif
46
47#define XDprintk if(h8_debug==-1)printk
48
49
50
51
52#define H8_MINOR_DEV 140
53
54
55
56
57static int h8_init(void);
58static int h8_display_blank(void);
59static int h8_display_unblank(void);
60
61static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
62
63static int h8_get_info(char *, char **, off_t, int);
64
65
66
67
68static void h8_hw_init(void);
69static void h8_start_new_cmd(void);
70static void h8_send_next_cmd_byte(void);
71static void h8_read_event_status(void);
72static void h8_sync(void);
73static void h8_q_cmd(u_char *, int, int);
74static void h8_cmd_done(h8_cmd_q_t *qp);
75static int h8_alloc_queues(void);
76
77static u_long h8_get_cpu_speed(void);
78static int h8_get_curr_temp(u_char curr_temp[]);
79static void h8_get_max_temp(void);
80static void h8_get_upper_therm_thold(void);
81static void h8_set_upper_therm_thold(int);
82static int h8_get_ext_status(u_char stat_word[]);
83
84static int h8_monitor_thread(void *);
85
86static int h8_manage_therm(void);
87static void h8_set_cpu_speed(int speed_divisor);
88
89static void h8_start_monitor_timer(unsigned long secs);
90static void h8_activate_monitor(unsigned long unused);
91
92
93extern void lca_clock_print(void);
94extern int lca_get_clock(void);
95extern void lca_clock_fiddle(int);
96
97static void h8_set_event_mask(int);
98static void h8_clear_event_mask(int);
99
100
101
102
103
104static struct timer_list h8_monitor_timer;
105static int h8_monitor_timer_active = 0;
106
107static char driver_version[] = "X0.0";
108
109static union intr_buf intrbuf;
110static int intr_buf_ptr;
111static union intr_buf xx;
112static u_char last_temp;
113
114
115
116
117#define H8_READ(a) inb((a))
118#define H8_WRITE(d,a) outb((d),(a))
119
120#define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
121#define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
122#define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
123#define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
124
125static unsigned int h8_base = H8_BASE_ADDR;
126static unsigned int h8_irq = H8_IRQ;
127static unsigned int h8_state = H8_IDLE;
128static unsigned int h8_index = -1;
129static unsigned int h8_enabled = 0;
130
131static LIST_HEAD(h8_actq);
132static LIST_HEAD(h8_cmdq);
133static LIST_HEAD(h8_freeq);
134
135
136
137
138static int cpu_speed_divisor = -1;
139static int h8_event_mask = 0;
140static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
141static unsigned int h8_command_mask = 0;
142static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
143static int h8_uthermal_window = UTH_HYSTERESIS;
144static int h8_debug = 0xfffffdfc;
145static int h8_ldamp = MHZ_115;
146static int h8_udamp = MHZ_57;
147static u_char h8_current_temp = 0;
148static u_char h8_system_temp = 0;
149static int h8_sync_channel = 0;
150static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
151static int h8_init_performed;
152
153
154static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
155
156
157
158
159static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
160{
161 u_char stat_reg, data_reg;
162 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
163
164 stat_reg = H8_GET_STATUS;
165 data_reg = H8_READ_DATA;
166
167 XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
168
169 switch (h8_state) {
170
171 case H8_IDLE: {
172 if (stat_reg & H8_OFULL) {
173 if (data_reg == H8_INTR) {
174 h8_state = H8_INTR_MODE;
175
176 WRITE_CMD(H8_RD_EVENT_STATUS);
177 intr_buf_ptr = 1;
178 WRITE_CMD(H8_RD_EVENT_STATUS);
179 } else {
180 Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
181 stat_reg, data_reg);
182 }
183 } else {
184 Dprintk("h8_intr: bogus interrupt\n");
185 }
186 break;
187 }
188 case H8_INTR_MODE: {
189 XDprintk("H8 intr/intr_mode\n");
190 if (data_reg == H8_BYTE_LEVEL_ACK) {
191 return;
192 } else if (data_reg == H8_CMD_ACK) {
193 return;
194 } else {
195 intrbuf.byte[intr_buf_ptr] = data_reg;
196 if(!intr_buf_ptr) {
197 h8_state = H8_IDLE;
198 h8_read_event_status();
199 }
200 intr_buf_ptr--;
201 }
202 break;
203 }
204
205 case H8_XMIT: {
206 XDprintk("H8 intr/xmit\n");
207
208 if (data_reg == H8_BYTE_LEVEL_ACK) {
209 XDprintk("H8 intr/xmit BYTE ACK\n");
210 qp->nacks++;
211 if (qp->nacks > qp->ncmd)
212 if(h8_debug & 0x1)
213 Dprintk("h8intr: bogus # of acks!\n");
214
215
216
217
218 if (qp->cnt < qp->ncmd) {
219 h8_send_next_cmd_byte();
220 }
221 return;
222
223 } else if (data_reg == H8_CMD_ACK) {
224 XDprintk("H8 intr/xmit CMD ACK\n");
225
226 if (qp->nrsp)
227 h8_state = H8_RCV;
228 else
229 h8_state = H8_IDLE;
230 qp->cnt = 0;
231 return;
232
233 } else if (data_reg == H8_NACK) {
234 XDprintk("h8_intr: NACK received restarting command\n");
235 qp->nacks = 0;
236 qp->cnt = 0;
237 h8_state = H8_IDLE;
238 WRITE_CMD(H8_SYNC);
239 return;
240 } else {
241 Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
242 return;
243 }
244 break;
245 }
246 case H8_RESYNC: {
247 XDprintk("H8 intr/resync\n");
248 if (data_reg == H8_BYTE_LEVEL_ACK) {
249 return;
250 } else if (data_reg == H8_SYNC_BYTE) {
251 h8_state = H8_IDLE;
252 if (!list_empty(&h8_actq))
253 h8_send_next_cmd_byte();
254 } else {
255 Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
256 return;
257 }
258 break;
259 }
260 case H8_RCV: {
261 XDprintk("H8 intr/rcv\n");
262 if (qp->cnt < qp->nrsp) {
263 qp->rcvbuf[qp->cnt] = data_reg;
264 qp->cnt++;
265
266 if (qp->cnt == qp->nrsp) {
267 h8_state = H8_IDLE;
268 list_del(&qp->link);
269 h8_cmd_done (qp);
270
271 if (!list_empty(&h8_cmdq))
272 h8_start_new_cmd();
273 }
274 return;
275 } else {
276 Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
277 }
278 break;
279 }
280 default:
281 Dprintk("H8 intr/unknown\n");
282 break;
283 }
284 return;
285}
286
287static void __exit h8_cleanup (void)
288{
289 remove_proc_entry("driver/h8", NULL);
290 release_region(h8_base, 8);
291 free_irq(h8_irq, NULL);
292}
293
294static int __init h8_init(void)
295{
296 if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
297 {
298 printk(KERN_ERR "H8: error: IRQ %d is not free\n", h8_irq);
299 return -EIO;
300 }
301 printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
302
303 create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
304
305 request_region(h8_base, 8, "h8");
306
307 h8_alloc_queues();
308
309 h8_hw_init();
310
311 kernel_thread(h8_monitor_thread, NULL, 0);
312
313 return 0;
314}
315
316module_init(h8_init);
317module_exit(h8_cleanup);
318
319static void __init h8_hw_init(void)
320{
321 u_char buf[H8_MAX_CMD_SIZE];
322
323
324 h8_set_cpu_speed(MHZ_230);
325
326
327
328
329 h8_sync();
330
331
332 h8_read_event_status();
333
334
335 buf[0] = H8_DEVICE_CONTROL;
336 buf[1] = 0xff;
337 buf[2] = 0x0;
338 h8_q_cmd(buf, 3, 1);
339
340
341 buf[0] = H8_DEVICE_CONTROL;
342 buf[1] = 0x0;
343 buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
344 H8_ENAB_LOW_SPD_IND;
345 h8_q_cmd(buf, 3, 1);
346
347 h8_enabled = 1;
348 return;
349}
350
351static int h8_get_info(char *buf, char **start, off_t fpos, int length)
352{
353#ifdef CONFIG_PROC_FS
354 char *p;
355
356 if (!h8_enabled)
357 return 0;
358 p = buf;
359
360
361
362
363
364
365
366
367
368
369 p += sprintf(p, "%s \n",
370 driver_version
371 );
372
373 return p - buf;
374#else
375 return 0;
376#endif
377}
378
379
380static int h8_display_blank(void)
381{
382#ifdef CONFIG_H8_DISPLAY_BLANK
383 int error;
384
385 if (!h8_enabled)
386 return 0;
387 error = h8_set_display_power_state(H8_STATE_STANDBY);
388 if (error == H8_SUCCESS)
389 return 1;
390 h8_error("set display standby", error);
391#endif
392 return 0;
393}
394
395
396static int h8_display_unblank(void)
397{
398#ifdef CONFIG_H8_DISPLAY_BLANK
399 int error;
400
401 if (!h8_enabled)
402 return 0;
403 error = h8_set_display_power_state(H8_STATE_READY);
404 if (error == H8_SUCCESS)
405 return 1;
406 h8_error("set display ready", error);
407#endif
408 return 0;
409}
410
411static int h8_alloc_queues(void)
412{
413 h8_cmd_q_t *qp;
414 unsigned long flags;
415 int i;
416
417 qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
418 GFP_KERNEL);
419
420 if (!qp) {
421 printk(KERN_ERR "H8: could not allocate memory for command queue\n");
422 return(0);
423 }
424
425 save_flags(flags); cli();
426 for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
427
428 list_add(&qp[i].link, &h8_freeq);
429 }
430 restore_flags(flags);
431 return (1);
432}
433
434
435
436
437void
438h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
439{
440 h8_cmd_q_t *qp;
441 unsigned long flags;
442 int i;
443
444
445 save_flags(flags); cli();
446 while (list_empty(&h8_freeq)) {
447 Dprintk("H8: need to allocate more cmd buffers\n");
448 restore_flags(flags);
449 h8_alloc_queues();
450 save_flags(flags); cli();
451 }
452
453 qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
454 list_del(&qp->link);
455
456 restore_flags(flags);
457
458
459 for (i = 0; i < cmd_size; i++)
460 qp->cmdbuf[i] = cmd[i];
461 qp->ncmd = cmd_size;
462 qp->nrsp = resp_size;
463
464
465 save_flags(flags); cli();
466
467
468 list_add(&qp->link, &h8_cmdq);
469
470 restore_flags(flags);
471
472 h8_start_new_cmd();
473}
474
475void
476h8_start_new_cmd(void)
477{
478 unsigned long flags;
479 h8_cmd_q_t *qp;
480
481 save_flags(flags); cli();
482 if (h8_state != H8_IDLE) {
483 if (h8_debug & 0x1)
484 Dprintk("h8_start_new_cmd: not idle\n");
485 restore_flags(flags);
486 return;
487 }
488
489 if (!list_empty(&h8_actq)) {
490 Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
491 restore_flags(flags);
492 return;
493 }
494
495 if (list_empty(&h8_cmdq)) {
496 Dprintk("h8_start_new_cmd: no command to dequeue\n");
497 restore_flags(flags);
498 return;
499 }
500
501
502
503
504 qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
505 list_del(&qp->link);
506
507 list_add(&qp->link, &h8_actq);
508 h8_state = H8_XMIT;
509 if (h8_debug & 0x1)
510 Dprintk("h8_start_new_cmd: Starting a command\n");
511
512 qp->cnt = 1;
513 WRITE_CMD(qp->cmdbuf[0]);
514
515 restore_flags(flags);
516 return;
517}
518
519void
520h8_send_next_cmd_byte(void)
521{
522 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
523 int cnt;
524
525 cnt = qp->cnt;
526 qp->cnt++;
527
528 if (h8_debug & 0x1)
529 Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
530 cnt, qp->cmdbuf[cnt]);
531
532 if (cnt) {
533 WRITE_DATA(qp->cmdbuf[cnt]);
534 } else {
535 WRITE_CMD(qp->cmdbuf[cnt]);
536 }
537 return;
538}
539
540
541
542
543void
544h8_sync(void)
545{
546 u_char buf[H8_MAX_CMD_SIZE];
547
548 buf[0] = H8_SYNC;
549 buf[1] = H8_SYNC_BYTE;
550 h8_q_cmd(buf, 2, 1);
551}
552
553
554
555
556
557void
558h8_read_event_status(void)
559{
560
561 if(h8_debug & 0x200)
562 printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word);
563
564
565
566
567 if (intrbuf.word & H8_DC_CHANGE) {
568 if(h8_debug & 0x4)
569 printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n");
570
571
572 h8_set_event_mask(H8_MANAGE_BATTERY);
573 wake_up(&h8_monitor_wait);
574 }
575
576 if (intrbuf.word & H8_POWER_BUTTON) {
577 printk(KERN_CRIT "Power switch pressed - please wait - preparing to power
578off\n");
579 h8_set_event_mask(H8_POWER_BUTTON);
580 wake_up(&h8_monitor_wait);
581 }
582
583
584
585
586 if (intrbuf.word & H8_THERMAL_THRESHOLD) {
587 if(h8_debug & 0x4)
588 printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLD\n");
589 h8_set_event_mask(H8_MANAGE_UTHERM);
590 wake_up(&h8_monitor_wait);
591 }
592
593
594
595
596 if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
597 if(h8_debug & 0x4)
598 printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n");
599
600 }
601 if (intrbuf.word & H8_EXT_BATT_STATUS) {
602 if(h8_debug & 0x4)
603 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n");
604
605 }
606 if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
607 if(h8_debug & 0x4)
608 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
609
610 }
611 if (intrbuf.word & H8_BATT_CHANGE_OVER) {
612 if(h8_debug & 0x4)
613 printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n");
614
615 }
616 if (intrbuf.word & H8_WATCHDOG) {
617 if(h8_debug & 0x4)
618 printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n");
619
620 }
621 if (intrbuf.word & H8_SHUTDOWN) {
622 if(h8_debug & 0x4)
623 printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n");
624
625 }
626 if (intrbuf.word & H8_KEYBOARD) {
627 if(h8_debug & 0x4)
628 printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n");
629
630 }
631 if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
632 if(h8_debug & 0x4)
633 printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
634
635 }
636 if (intrbuf.word & H8_INT_BATT_LOW) {
637 if(h8_debug & 0x4)
638 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post
639
640 }
641 if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
642 if(h8_debug & 0x4)
643 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n");
644
645 }
646 if (intrbuf.word & H8_INT_BATT_STATUS) {
647 if(h8_debug & 0x4)
648 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n");
649
650 }
651 if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
652 if(h8_debug & 0x4)
653 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
654
655 }
656 if (intrbuf.word & H8_EXT_BATT_LOW) {
657 if(h8_debug & 0x4)
658 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n");
659
660
661 }
662
663 return;
664}
665
666
667
668
669static void
670h8_cmd_done(h8_cmd_q_t *qp)
671{
672
673
674 switch (qp->cmdbuf[0]) {
675 case H8_SYNC:
676 if (h8_debug & 0x40000)
677 printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n",
678 qp->rcvbuf[0]);
679 list_add(&qp->link, &h8_freeq);
680 break;
681
682 case H8_RD_SN:
683 case H8_RD_ENET_ADDR:
684 printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n",
685 qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
686 qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
687 list_add(&qp->link, &h8_freeq);
688 break;
689
690 case H8_RD_HW_VER:
691 case H8_RD_MIC_VER:
692 case H8_RD_MAX_TEMP:
693 printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %d\n",
694 qp->rcvbuf[0], qp->rcvbuf[1]);
695 list_add(&qp->link, &h8_freeq);
696 break;
697
698 case H8_RD_MIN_TEMP:
699 printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %d\n",
700 qp->rcvbuf[0], qp->rcvbuf[1]);
701 list_add(&qp->link, &h8_freeq);
702 break;
703
704 case H8_RD_CURR_TEMP:
705 h8_sync_channel |= H8_RD_CURR_TEMP;
706 xx.byte[0] = qp->rcvbuf[0];
707 xx.byte[1] = qp->rcvbuf[1];
708 wake_up(&h8_sync_wait);
709 list_add(&qp->link, &h8_freeq);
710 break;
711
712 case H8_RD_SYS_VARIENT:
713 case H8_RD_PWR_ON_CYCLES:
714 printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command done\n");
715 break;
716
717 case H8_RD_PWR_ON_SECS:
718 printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n");
719 break;
720
721 case H8_RD_RESET_STATUS:
722 case H8_RD_PWR_DN_STATUS:
723 case H8_RD_EVENT_STATUS:
724 case H8_RD_ROM_CKSM:
725 case H8_RD_EXT_STATUS:
726 xx.byte[1] = qp->rcvbuf[0];
727 xx.byte[0] = qp->rcvbuf[1];
728 h8_sync_channel |= H8_GET_EXT_STATUS;
729 wake_up(&h8_sync_wait);
730 list_add(&qp->link, &h8_freeq);
731 break;
732
733 case H8_RD_USER_CFG:
734 case H8_RD_INT_BATT_VOLT:
735 case H8_RD_DC_INPUT_VOLT:
736 case H8_RD_HORIZ_PTR_VOLT:
737 case H8_RD_VERT_PTR_VOLT:
738 case H8_RD_EEPROM_STATUS:
739 case H8_RD_ERR_STATUS:
740 case H8_RD_NEW_BUSY_SPEED:
741 case H8_RD_CONFIG_INTERFACE:
742 case H8_RD_INT_BATT_STATUS:
743 printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %x\n",
744 qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
745 list_add(&qp->link, &h8_freeq);
746 break;
747
748 case H8_RD_EXT_BATT_STATUS:
749 case H8_RD_PWR_UP_STATUS:
750 case H8_RD_EVENT_STATUS_MASK:
751 case H8_CTL_EMU_BITPORT:
752 case H8_DEVICE_CONTROL:
753 if(h8_debug & 0x20000) {
754 printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%x\n",
755 qp->rcvbuf[0]);
756 }
757 list_add(&qp->link, &h8_freeq);
758 break;
759
760 case H8_CTL_TFT_BRT_DC:
761 case H8_CTL_WATCHDOG:
762 case H8_CTL_MIC_PROT:
763 case H8_CTL_INT_BATT_CHG:
764 case H8_CTL_EXT_BATT_CHG:
765 case H8_CTL_MARK_SPACE:
766 case H8_CTL_MOUSE_SENSITIVITY:
767 case H8_CTL_DIAG_MODE:
768 case H8_CTL_IDLE_AND_BUSY_SPDS:
769 printk(KERN_DEBUG "H8: Idle and busy speed command done\n");
770 break;
771
772 case H8_CTL_TFT_BRT_BATT:
773 case H8_CTL_UPPER_TEMP:
774 if(h8_debug & 0x10) {
775 XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
776 qp->rcvbuf[0]);
777 }
778 list_add(&qp->link, &h8_freeq);
779 break;
780
781 case H8_CTL_LOWER_TEMP:
782 case H8_CTL_TEMP_CUTOUT:
783 case H8_CTL_WAKEUP:
784 case H8_CTL_CHG_THRESHOLD:
785 case H8_CTL_TURBO_MODE:
786 case H8_SET_DIAG_STATUS:
787 case H8_SOFTWARE_RESET:
788 case H8_RECAL_PTR:
789 case H8_SET_INT_BATT_PERCENT:
790 case H8_WRT_CFG_INTERFACE_REG:
791 case H8_WRT_EVENT_STATUS_MASK:
792 case H8_ENTER_POST_MODE:
793 case H8_EXIT_POST_MODE:
794 case H8_RD_EEPROM:
795 case H8_WRT_EEPROM:
796 case H8_WRT_TO_STATUS_DISP:
797 printk("H8: Write IO status display command done\n");
798 break;
799
800 case H8_DEFINE_SPC_CHAR:
801 case H8_DEFINE_TABLE_STRING_ENTRY:
802 case H8_PERFORM_EMU_CMD:
803 case H8_EMU_RD_REG:
804 case H8_EMU_WRT_REG:
805 case H8_EMU_RD_RAM:
806 case H8_EMU_WRT_RAM:
807 case H8_BQ_RD_REG:
808 case H8_BQ_WRT_REG:
809 case H8_PWR_OFF:
810 printk (KERN_DEBUG "H8: misc command completed\n");
811 break;
812 }
813 return;
814}
815
816
817
818
819
820
821
822int
823h8_get_curr_temp(u_char curr_temp[])
824{
825 u_char buf[H8_MAX_CMD_SIZE];
826 unsigned long flags;
827
828 memset(buf, 0, H8_MAX_CMD_SIZE);
829 buf[0] = H8_RD_CURR_TEMP;
830
831 h8_q_cmd(buf, 1, 2);
832
833 save_flags(flags); cli();
834
835 while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
836 sleep_on(&h8_sync_wait);
837
838 restore_flags(flags);
839
840 h8_sync_channel &= ~H8_RD_CURR_TEMP;
841 curr_temp[0] = xx.byte[0];
842 curr_temp[1] = xx.byte[1];
843 xx.word = 0;
844
845 if(h8_debug & 0x8)
846 printk("H8: curr CPU temp %d, Sys temp %d\n",
847 curr_temp[0], curr_temp[1]);
848 return 0;
849}
850
851static void
852h8_get_max_temp(void)
853{
854 u_char buf[H8_MAX_CMD_SIZE];
855
856 buf[0] = H8_RD_MAX_TEMP;
857 h8_q_cmd(buf, 1, 2);
858}
859
860
861
862
863
864
865static void
866h8_set_upper_therm_thold(int thold)
867{
868 u_char buf[H8_MAX_CMD_SIZE];
869
870
871 buf[0] = H8_CTL_UPPER_TEMP;
872 buf[1] = 0x0;
873 buf[2] = 0x0;
874 h8_q_cmd(buf, 3, 1);
875
876
877 buf[0] = H8_CTL_UPPER_TEMP;
878 buf[1] = 0x0;
879 buf[2] = thold;
880 h8_q_cmd(buf, 3, 1);
881}
882
883static void
884h8_get_upper_therm_thold(void)
885{
886 u_char buf[H8_MAX_CMD_SIZE];
887
888 buf[0] = H8_CTL_UPPER_TEMP;
889 buf[1] = 0xff;
890 buf[2] = 0;
891 h8_q_cmd(buf, 3, 1);
892}
893
894
895
896
897
898
899int
900h8_get_ext_status(u_char stat_word[])
901{
902 u_char buf[H8_MAX_CMD_SIZE];
903 unsigned long flags;
904
905 memset(buf, 0, H8_MAX_CMD_SIZE);
906 buf[0] = H8_RD_EXT_STATUS;
907
908 h8_q_cmd(buf, 1, 2);
909
910 save_flags(flags); cli();
911
912 while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
913 sleep_on(&h8_sync_wait);
914
915 restore_flags(flags);
916
917 h8_sync_channel &= ~H8_GET_EXT_STATUS;
918 stat_word[0] = xx.byte[0];
919 stat_word[1] = xx.byte[1];
920 xx.word = 0;
921
922 if(h8_debug & 0x8)
923 printk("H8: curr ext status %x, %x\n",
924 stat_word[0], stat_word[1]);
925
926 return 0;
927}
928
929
930
931
932
933
934
935
936int
937h8_monitor_thread(void * unused)
938{
939 u_char curr_temp[2];
940
941
942
943
944
945
946
947
948 h8_get_curr_temp(curr_temp);
949
950 printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]);
951
952 if(curr_temp[0] >= h8_uthermal_threshold) {
953 h8_set_event_mask(H8_MANAGE_UTHERM);
954 h8_manage_therm();
955 } else {
956
957
958
959
960 h8_set_upper_therm_thold(h8_uthermal_threshold);
961 }
962
963 for(;;) {
964 sleep_on(&h8_monitor_wait);
965
966 if(h8_debug & 0x2)
967 printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n",
968 h8_event_mask);
969
970 if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
971 h8_manage_therm();
972 }
973
974#if 0
975 if (h8_event_mask & H8_POWER_BUTTON) {
976 h8_system_down();
977 }
978
979
980
981
982
983 if (h8_event_mask & H8_MANAGE_BATTERY) {
984 h8_run_level_3_manage(H8_RUN);
985 h8_clear_event_mask(H8_MANAGE_BATTERY);
986 }
987#endif
988 }
989}
990
991
992
993
994
995
996
997
998
999
1000
1001
1002int
1003h8_manage_therm(void)
1004{
1005 u_char curr_temp[2];
1006
1007 if(h8_event_mask & H8_MANAGE_UTHERM) {
1008
1009 if(h8_debug & 0x10)
1010 printk(KERN_WARNING "H8: Thermal threshold %d F reached\n",
1011 h8_uthermal_threshold);
1012 h8_set_cpu_speed(h8_udamp);
1013 h8_clear_event_mask(H8_MANAGE_UTHERM);
1014 h8_set_event_mask(H8_MANAGE_LTHERM);
1015
1016 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1017 } else if (h8_event_mask & H8_MANAGE_LTHERM) {
1018
1019
1020 h8_get_curr_temp(curr_temp);
1021 last_temp = curr_temp[0];
1022 if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
1023 {
1024
1025
1026 h8_set_upper_therm_thold(h8_uthermal_threshold);
1027 h8_set_cpu_speed(h8_ldamp);
1028 if(h8_debug & 0x10)
1029 printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n",
1030 h8_ldamp);
1031 h8_clear_event_mask(H8_MANAGE_LTHERM);
1032 }
1033 else
1034 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1035 } else {
1036
1037 }
1038 return 0;
1039}
1040
1041
1042
1043
1044
1045void
1046h8_set_cpu_speed(int speed_divisor)
1047{
1048
1049#ifdef NOT_YET
1050
1051
1052
1053
1054
1055
1056
1057 switch (speed_divisor) {
1058 case 0:
1059 global_rpb_counter = rpb->rpb_counter * 2L;
1060 break;
1061 case 1:
1062 global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
1063 break;
1064 case 3:
1065 global_rpb_counter = rpb->rpb_counter / 2L;
1066 break;
1067 case 4:
1068 global_rpb_counter = rpb->rpb_counter / 4L;
1069 break;
1070 case 5:
1071 global_rpb_counter = rpb->rpb_counter / 8L;
1072 break;
1073
1074
1075
1076
1077 default:
1078 global_rpb_counter = rpb->rpb_counter;
1079 break;
1080 }
1081#endif
1082
1083 if(h8_debug & 0x8)
1084 printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n",
1085 speed_tab[speed_divisor]);
1086
1087
1088 lca_clock_fiddle(speed_divisor);
1089}
1090
1091
1092
1093
1094
1095u_long
1096h8_get_cpu_speed(void)
1097{
1098 u_long speed = 0;
1099 u_long counter;
1100
1101#ifdef NOT_YET
1102 counter = rpb->rpb_counter / 1000000L;
1103
1104 switch (alphabook_get_clock()) {
1105 case 0:
1106 speed = counter * 2L;
1107 break;
1108 case 1:
1109 speed = counter * 4L / 3L ;
1110 break;
1111 case 2:
1112 speed = counter;
1113 break;
1114 case 3:
1115 speed = counter / 2L;
1116 break;
1117 case 4:
1118 speed = counter / 4L;
1119 break;
1120 case 5:
1121 speed = counter / 8L;
1122 break;
1123 default:
1124 break;
1125 }
1126 if(h8_debug & 0x8)
1127 printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed);
1128#endif
1129 return speed;
1130}
1131
1132static void
1133h8_activate_monitor(unsigned long unused)
1134{
1135 unsigned long flags;
1136
1137 save_flags(flags); cli();
1138 h8_monitor_timer_active = 0;
1139 restore_flags(flags);
1140
1141 wake_up(&h8_monitor_wait);
1142}
1143
1144static void
1145h8_start_monitor_timer(unsigned long secs)
1146{
1147 unsigned long flags;
1148
1149 if (h8_monitor_timer_active)
1150 return;
1151
1152 save_flags(flags); cli();
1153 h8_monitor_timer_active = 1;
1154 restore_flags(flags);
1155
1156 init_timer(&h8_monitor_timer);
1157 h8_monitor_timer.function = h8_activate_monitor;
1158 h8_monitor_timer.expires = secs * HZ + jiffies;
1159 add_timer(&h8_monitor_timer);
1160}
1161
1162static void h8_set_event_mask(int mask)
1163{
1164 unsigned long flags;
1165
1166 save_flags(flags); cli();
1167 h8_event_mask |= mask;
1168 restore_flags(flags);
1169}
1170
1171static void h8_clear_event_mask(int mask)
1172{
1173 unsigned long flags;
1174
1175 save_flags(flags); cli();
1176 h8_event_mask &= (~mask);
1177 restore_flags(flags);
1178}
1179
1180MODULE_LICENSE("GPL");
1181EXPORT_NO_SYMBOLS;
1182