Portability cleanup as required by Linus.
[linux-2.6/linux-mips.git] / drivers / char / h8.c
blobacc898cb8c42aabb252a1e732a8c124d7a3f37bc
1 /*
2 * Hitachi H8/337 Microcontroller driver
4 * The H8 is used to deal with the power and thermal environment
5 * of a system.
7 * Fixes:
8 * June 1999, AV added releasing /proc/driver/h8
9 * Feb 2000, Borislav Deianov
10 * changed queues to use list.h instead of lists.h
13 #include <linux/config.h>
14 #include <linux/module.h>
16 #include <asm/system.h>
17 #include <asm/segment.h>
18 #include <asm/io.h>
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>
34 #define __KERNEL_SYSCALLS__
35 #include <asm/unistd.h>
37 #include "h8.h"
39 #define DEBUG_H8
41 #ifdef DEBUG_H8
42 #define Dprintk printk
43 #else
44 #define Dprintk
45 #endif
47 #define XDprintk if(h8_debug==-1)printk
50 * The h8 device is one of the misc char devices.
52 #define H8_MINOR_DEV 140
55 * Forward declarations.
57 static int h8_init(void);
58 int h8_display_blank(void);
59 int h8_display_unblank(void);
61 static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
63 static int h8_get_info(char *, char **, off_t, int);
66 * Support Routines.
68 static void h8_hw_init(void);
69 static void h8_start_new_cmd(void);
70 static void h8_send_next_cmd_byte(void);
71 static void h8_read_event_status(void);
72 static void h8_sync(void);
73 static void h8_q_cmd(u_char *, int, int);
74 static void h8_cmd_done(h8_cmd_q_t *qp);
75 static int h8_alloc_queues(void);
77 static u_long h8_get_cpu_speed(void);
78 static int h8_get_curr_temp(u_char curr_temp[]);
79 static void h8_get_max_temp(void);
80 static void h8_get_upper_therm_thold(void);
81 static void h8_set_upper_therm_thold(int);
82 static int h8_get_ext_status(u_char stat_word[]);
84 static int h8_monitor_thread(void *);
86 static int h8_manage_therm(void);
87 static void h8_set_cpu_speed(int speed_divisor);
89 static void h8_start_monitor_timer(unsigned long secs);
90 static void h8_activate_monitor(unsigned long unused);
92 /* in arch/alpha/kernel/lca.c */
93 extern void lca_clock_print(void);
94 extern int lca_get_clock(void);
95 extern void lca_clock_fiddle(int);
97 static void h8_set_event_mask(int);
98 static void h8_clear_event_mask(int);
101 * Driver structures
104 static struct timer_list h8_monitor_timer;
105 static int h8_monitor_timer_active = 0;
107 static char driver_version[] = "X0.0";/* no spaces */
109 static struct file_operations h8_fops = {
110 /* twelve lines of crap^WNULLs were here */
113 static struct miscdevice h8_device = {
114 H8_MINOR_DEV,
115 "h8",
116 &h8_fops
119 union intr_buf intrbuf;
120 int intr_buf_ptr;
121 union intr_buf xx;
122 u_char last_temp;
125 * I/O Macros for register reads and writes.
127 #define H8_READ(a) inb((a))
128 #define H8_WRITE(d,a) outb((d),(a))
130 #define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
131 #define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
132 #define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
133 #define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
135 unsigned int h8_base = H8_BASE_ADDR;
136 unsigned int h8_irq = H8_IRQ;
137 unsigned int h8_state = H8_IDLE;
138 unsigned int h8_index = -1;
139 unsigned int h8_enabled = 0;
141 LIST_HEAD(h8_actq);
142 LIST_HEAD(h8_cmdq);
143 LIST_HEAD(h8_freeq);
146 * Globals used in thermal control of Alphabook1.
148 int cpu_speed_divisor = -1;
149 int h8_event_mask = 0;
150 DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
151 unsigned int h8_command_mask = 0;
152 int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
153 int h8_uthermal_window = UTH_HYSTERESIS;
154 int h8_debug = 0xfffffdfc;
155 int h8_ldamp = MHZ_115;
156 int h8_udamp = MHZ_57;
157 u_char h8_current_temp = 0;
158 u_char h8_system_temp = 0;
159 int h8_sync_channel = 0;
160 DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
161 int h8_init_performed;
163 /* CPU speeds and clock divisor values */
164 int speed_tab[6] = {230, 153, 115, 57, 28, 14};
167 * H8 interrupt handler
169 static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
171 u_char stat_reg, data_reg;
172 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
174 stat_reg = H8_GET_STATUS;
175 data_reg = H8_READ_DATA;
177 XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
179 switch (h8_state) {
180 /* Response to an asynchronous event. */
181 case H8_IDLE: { /* H8_IDLE */
182 if (stat_reg & H8_OFULL) {
183 if (data_reg == H8_INTR) {
184 h8_state = H8_INTR_MODE;
185 /* Executing a command to determine what happened. */
186 WRITE_CMD(H8_RD_EVENT_STATUS);
187 intr_buf_ptr = 1;
188 WRITE_CMD(H8_RD_EVENT_STATUS);
189 } else {
190 Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
191 stat_reg, data_reg);
193 } else {
194 Dprintk("h8_intr: bogus interrupt\n");
196 break;
198 case H8_INTR_MODE: { /* H8_INTR_MODE */
199 XDprintk("H8 intr/intr_mode\n");
200 if (data_reg == H8_BYTE_LEVEL_ACK) {
201 return;
202 } else if (data_reg == H8_CMD_ACK) {
203 return;
204 } else {
205 intrbuf.byte[intr_buf_ptr] = data_reg;
206 if(!intr_buf_ptr) {
207 h8_state = H8_IDLE;
208 h8_read_event_status();
210 intr_buf_ptr--;
212 break;
214 /* Placed in this state by h8_start_new_cmd(). */
215 case H8_XMIT: { /* H8_XMIT */
216 XDprintk("H8 intr/xmit\n");
217 /* If a byte level acknowledgement has been received */
218 if (data_reg == H8_BYTE_LEVEL_ACK) {
219 XDprintk("H8 intr/xmit BYTE ACK\n");
220 qp->nacks++;
221 if (qp->nacks > qp->ncmd)
222 if(h8_debug & 0x1)
223 Dprintk("h8intr: bogus # of acks!\n");
225 * If the number of bytes sent is less than the total
226 * number of bytes in the command.
228 if (qp->cnt < qp->ncmd) {
229 h8_send_next_cmd_byte();
231 return;
232 /* If the complete command has produced an acknowledgement. */
233 } else if (data_reg == H8_CMD_ACK) {
234 XDprintk("H8 intr/xmit CMD ACK\n");
235 /* If there are response bytes */
236 if (qp->nrsp)
237 h8_state = H8_RCV;
238 else
239 h8_state = H8_IDLE;
240 qp->cnt = 0;
241 return;
242 /* Error, need to start over with a clean slate. */
243 } else if (data_reg == H8_NACK) {
244 XDprintk("h8_intr: NACK received restarting command\n");
245 qp->nacks = 0;
246 qp->cnt = 0;
247 h8_state = H8_IDLE;
248 WRITE_CMD(H8_SYNC);
249 return;
250 } else {
251 Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
252 return;
254 break;
256 case H8_RESYNC: { /* H8_RESYNC */
257 XDprintk("H8 intr/resync\n");
258 if (data_reg == H8_BYTE_LEVEL_ACK) {
259 return;
260 } else if (data_reg == H8_SYNC_BYTE) {
261 h8_state = H8_IDLE;
262 if (!list_empty(&h8_actq))
263 h8_send_next_cmd_byte();
264 } else {
265 Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
266 return;
268 break;
270 case H8_RCV: { /* H8_RCV */
271 XDprintk("H8 intr/rcv\n");
272 if (qp->cnt < qp->nrsp) {
273 qp->rcvbuf[qp->cnt] = data_reg;
274 qp->cnt++;
275 /* If command reception finished. */
276 if (qp->cnt == qp->nrsp) {
277 h8_state = H8_IDLE;
278 list_del(&qp->link);
279 h8_cmd_done (qp);
280 /* More commands to send over? */
281 if (!list_empty(&h8_cmdq))
282 h8_start_new_cmd();
284 return;
285 } else {
286 Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
288 break;
290 default: /* default */
291 Dprintk("H8 intr/unknown\n");
292 break;
294 return;
297 static void __exit h8_cleanup (void)
299 remove_proc_entry("driver/h8", NULL);
300 misc_deregister(&h8_device);
301 release_region(h8_base, 8);
302 free_irq(h8_irq, NULL);
305 static int __init h8_init(void)
307 if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
309 printk(KERN_ERR "H8: error: IRQ %d is not free\n", h8_irq);
310 return -EIO;
312 printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
314 create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
316 misc_register(&h8_device);
317 request_region(h8_base, 8, "h8");
319 h8_alloc_queues();
321 h8_hw_init();
323 kernel_thread(h8_monitor_thread, NULL, 0);
325 return 0;
328 module_init(h8_init);
329 module_exit(h8_cleanup);
331 static void __init h8_hw_init(void)
333 u_char buf[H8_MAX_CMD_SIZE];
335 /* set CPU speed to max for booting */
336 h8_set_cpu_speed(MHZ_230);
339 * Initialize the H8
341 h8_sync(); /* activate interrupts */
343 /* To clear conditions left by console */
344 h8_read_event_status();
346 /* Perform a conditioning read */
347 buf[0] = H8_DEVICE_CONTROL;
348 buf[1] = 0xff;
349 buf[2] = 0x0;
350 h8_q_cmd(buf, 3, 1);
352 /* Turn on built-in and external mice, capture power switch */
353 buf[0] = H8_DEVICE_CONTROL;
354 buf[1] = 0x0;
355 buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
356 /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
357 h8_q_cmd(buf, 3, 1);
359 h8_enabled = 1;
360 return;
363 static int h8_get_info(char *buf, char **start, off_t fpos, int length)
365 #ifdef CONFIG_PROC_FS
366 char *p;
368 if (!h8_enabled)
369 return 0;
370 p = buf;
374 0) Linux driver version (this will change if format changes)
381 p += sprintf(p, "%s \n",
382 driver_version
385 return p - buf;
386 #else
387 return 0;
388 #endif
391 /* Called from console driver -- must make sure h8_enabled. */
392 int h8_display_blank(void)
394 #ifdef CONFIG_H8_DISPLAY_BLANK
395 int error;
397 if (!h8_enabled)
398 return 0;
399 error = h8_set_display_power_state(H8_STATE_STANDBY);
400 if (error == H8_SUCCESS)
401 return 1;
402 h8_error("set display standby", error);
403 #endif
404 return 0;
407 /* Called from console driver -- must make sure h8_enabled. */
408 int h8_display_unblank(void)
410 #ifdef CONFIG_H8_DISPLAY_BLANK
411 int error;
413 if (!h8_enabled)
414 return 0;
415 error = h8_set_display_power_state(H8_STATE_READY);
416 if (error == H8_SUCCESS)
417 return 1;
418 h8_error("set display ready", error);
419 #endif
420 return 0;
424 h8_alloc_queues(void)
426 h8_cmd_q_t *qp;
427 unsigned long flags;
428 int i;
430 qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
431 GFP_KERNEL);
433 if (!qp) {
434 printk("H8: could not allocate memory for command queue\n");
435 return(0);
437 /* add to the free queue */
438 save_flags(flags); cli();
439 for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
440 /* place each at front of freeq */
441 list_add(&qp[i].link, &h8_freeq);
443 restore_flags(flags);
444 return (1);
448 * Basic means by which commands are sent to the H8.
450 void
451 h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
453 h8_cmd_q_t *qp;
454 unsigned long flags;
455 int i;
457 /* get cmd buf */
458 save_flags(flags); cli();
459 while (list_empty(&h8_freeq)) {
460 Dprintk("H8: need to allocate more cmd buffers\n");
461 restore_flags(flags);
462 h8_alloc_queues();
463 save_flags(flags); cli();
465 /* get first element from queue */
466 qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
467 list_del(&qp->link);
469 restore_flags(flags);
471 /* fill it in */
472 for (i = 0; i < cmd_size; i++)
473 qp->cmdbuf[i] = cmd[i];
474 qp->ncmd = cmd_size;
475 qp->nrsp = resp_size;
477 /* queue it at the end of the cmd queue */
478 save_flags(flags); cli();
480 /* XXX this actually puts it at the start of cmd queue, bug? */
481 list_add(&qp->link, &h8_cmdq);
483 restore_flags(flags);
485 h8_start_new_cmd();
488 void
489 h8_start_new_cmd(void)
491 unsigned long flags;
492 h8_cmd_q_t *qp;
494 save_flags(flags); cli();
495 if (h8_state != H8_IDLE) {
496 if (h8_debug & 0x1)
497 Dprintk("h8_start_new_cmd: not idle\n");
498 restore_flags(flags);
499 return;
502 if (!list_empty(&h8_actq)) {
503 Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
504 restore_flags(flags);
505 return;
508 if (list_empty(&h8_cmdq)) {
509 Dprintk("h8_start_new_cmd: no command to dequeue\n");
510 restore_flags(flags);
511 return;
514 * Take first command off of the command queue and put
515 * it on the active queue.
517 qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
518 list_del(&qp->link);
519 /* XXX should this go to the end of the active queue? */
520 list_add(&qp->link, &h8_actq);
521 h8_state = H8_XMIT;
522 if (h8_debug & 0x1)
523 Dprintk("h8_start_new_cmd: Starting a command\n");
525 qp->cnt = 1;
526 WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */
528 restore_flags(flags);
529 return;
532 void
533 h8_send_next_cmd_byte(void)
535 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
536 int cnt;
538 cnt = qp->cnt;
539 qp->cnt++;
541 if (h8_debug & 0x1)
542 Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
543 cnt, qp->cmdbuf[cnt]);
545 if (cnt) {
546 WRITE_DATA(qp->cmdbuf[cnt]);
547 } else {
548 WRITE_CMD(qp->cmdbuf[cnt]);
550 return;
554 * Synchronize H8 communications channel for command transmission.
556 void
557 h8_sync(void)
559 u_char buf[H8_MAX_CMD_SIZE];
561 buf[0] = H8_SYNC;
562 buf[1] = H8_SYNC_BYTE;
563 h8_q_cmd(buf, 2, 1);
567 * Responds to external interrupt. Reads event status word and
568 * decodes type of interrupt.
570 void
571 h8_read_event_status(void)
574 if(h8_debug & 0x200)
575 printk("h8_read_event_status: value 0x%x\n", intrbuf.word);
578 * Power related items
580 if (intrbuf.word & H8_DC_CHANGE) {
581 if(h8_debug & 0x4)
582 printk("h8_read_event_status: DC_CHANGE\n");
583 /* see if dc added or removed, set batt/dc flag, send event */
585 h8_set_event_mask(H8_MANAGE_BATTERY);
586 wake_up(&h8_monitor_wait);
589 if (intrbuf.word & H8_POWER_BUTTON) {
590 printk("Power switch pressed - please wait - preparing to power
591 off\n");
592 h8_set_event_mask(H8_POWER_BUTTON);
593 wake_up(&h8_monitor_wait);
597 * Thermal related items
599 if (intrbuf.word & H8_THERMAL_THRESHOLD) {
600 if(h8_debug & 0x4)
601 printk("h8_read_event_status: THERMAL_THRESHOLD\n");
602 h8_set_event_mask(H8_MANAGE_UTHERM);
603 wake_up(&h8_monitor_wait);
607 * nops -for now
609 if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
610 if(h8_debug & 0x4)
611 printk("h8_read_event_status: DOCKING_STATION_STATUS\n");
612 /* read_ext_status */
614 if (intrbuf.word & H8_EXT_BATT_STATUS) {
615 if(h8_debug & 0x4)
616 printk("h8_read_event_status: EXT_BATT_STATUS\n");
619 if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
620 if(h8_debug & 0x4)
621 printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
624 if (intrbuf.word & H8_BATT_CHANGE_OVER) {
625 if(h8_debug & 0x4)
626 printk("h8_read_event_status: BATT_CHANGE_OVER\n");
629 if (intrbuf.word & H8_WATCHDOG) {
630 if(h8_debug & 0x4)
631 printk("h8_read_event_status: WATCHDOG\n");
632 /* nop */
634 if (intrbuf.word & H8_SHUTDOWN) {
635 if(h8_debug & 0x4)
636 printk("h8_read_event_status: SHUTDOWN\n");
637 /* nop */
639 if (intrbuf.word & H8_KEYBOARD) {
640 if(h8_debug & 0x4)
641 printk("h8_read_event_status: KEYBOARD\n");
642 /* nop */
644 if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
645 if(h8_debug & 0x4)
646 printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
647 /* read_ext_status*/
649 if (intrbuf.word & H8_INT_BATT_LOW) {
650 if(h8_debug & 0x4)
651 printk("h8_read_event_status: INT_BATT_LOW\n");
652 /* post event, warn user */
654 if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
655 if(h8_debug & 0x4)
656 printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n");
657 /* nop - happens often */
659 if (intrbuf.word & H8_INT_BATT_STATUS) {
660 if(h8_debug & 0x4)
661 printk("h8_read_event_status: INT_BATT_STATUS\n");
664 if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
665 if(h8_debug & 0x4)
666 printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
667 /* nop - happens often */
669 if (intrbuf.word & H8_EXT_BATT_LOW) {
670 if(h8_debug & 0x4)
671 printk("h8_read_event_status: EXT_BATT_LOW\n");
672 /*if no internal, post event, warn user */
673 /* else nop */
676 return;
680 * Function called when H8 has performed requested command.
682 void
683 h8_cmd_done(h8_cmd_q_t *qp)
686 /* what to do */
687 switch (qp->cmdbuf[0]) {
688 case H8_SYNC:
689 if (h8_debug & 0x40000)
690 printk("H8: Sync command done - byte returned was 0x%x\n",
691 qp->rcvbuf[0]);
692 list_add(&qp->link, &h8_freeq);
693 break;
695 case H8_RD_SN:
696 case H8_RD_ENET_ADDR:
697 printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n",
698 qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
699 qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
700 list_add(&qp->link, &h8_freeq);
701 break;
703 case H8_RD_HW_VER:
704 case H8_RD_MIC_VER:
705 case H8_RD_MAX_TEMP:
706 printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
707 qp->rcvbuf[0], qp->rcvbuf[1]);
708 list_add(&qp->link, &h8_freeq);
709 break;
711 case H8_RD_MIN_TEMP:
712 printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
713 qp->rcvbuf[0], qp->rcvbuf[1]);
714 list_add(&qp->link, &h8_freeq);
715 break;
717 case H8_RD_CURR_TEMP:
718 h8_sync_channel |= H8_RD_CURR_TEMP;
719 xx.byte[0] = qp->rcvbuf[0];
720 xx.byte[1] = qp->rcvbuf[1];
721 wake_up(&h8_sync_wait);
722 list_add(&qp->link, &h8_freeq);
723 break;
725 case H8_RD_SYS_VARIENT:
726 case H8_RD_PWR_ON_CYCLES:
727 printk(" H8: RD_PWR_ON_CYCLES command done\n");
728 break;
730 case H8_RD_PWR_ON_SECS:
731 printk("H8: RD_PWR_ON_SECS command done\n");
732 break;
734 case H8_RD_RESET_STATUS:
735 case H8_RD_PWR_DN_STATUS:
736 case H8_RD_EVENT_STATUS:
737 case H8_RD_ROM_CKSM:
738 case H8_RD_EXT_STATUS:
739 xx.byte[1] = qp->rcvbuf[0];
740 xx.byte[0] = qp->rcvbuf[1];
741 h8_sync_channel |= H8_GET_EXT_STATUS;
742 wake_up(&h8_sync_wait);
743 list_add(&qp->link, &h8_freeq);
744 break;
746 case H8_RD_USER_CFG:
747 case H8_RD_INT_BATT_VOLT:
748 case H8_RD_DC_INPUT_VOLT:
749 case H8_RD_HORIZ_PTR_VOLT:
750 case H8_RD_VERT_PTR_VOLT:
751 case H8_RD_EEPROM_STATUS:
752 case H8_RD_ERR_STATUS:
753 case H8_RD_NEW_BUSY_SPEED:
754 case H8_RD_CONFIG_INTERFACE:
755 case H8_RD_INT_BATT_STATUS:
756 printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
757 qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
758 list_add(&qp->link, &h8_freeq);
759 break;
761 case H8_RD_EXT_BATT_STATUS:
762 case H8_RD_PWR_UP_STATUS:
763 case H8_RD_EVENT_STATUS_MASK:
764 case H8_CTL_EMU_BITPORT:
765 case H8_DEVICE_CONTROL:
766 if(h8_debug & 0x20000) {
767 printk("H8: Device control cmd done - byte returned was 0x%x\n",
768 qp->rcvbuf[0]);
770 list_add(&qp->link, &h8_freeq);
771 break;
773 case H8_CTL_TFT_BRT_DC:
774 case H8_CTL_WATCHDOG:
775 case H8_CTL_MIC_PROT:
776 case H8_CTL_INT_BATT_CHG:
777 case H8_CTL_EXT_BATT_CHG:
778 case H8_CTL_MARK_SPACE:
779 case H8_CTL_MOUSE_SENSITIVITY:
780 case H8_CTL_DIAG_MODE:
781 case H8_CTL_IDLE_AND_BUSY_SPDS:
782 printk("H8: Idle and busy speed command done\n");
783 break;
785 case H8_CTL_TFT_BRT_BATT:
786 case H8_CTL_UPPER_TEMP:
787 if(h8_debug & 0x10) {
788 XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
789 qp->rcvbuf[0]);
791 list_add(&qp->link, &h8_freeq);
792 break;
794 case H8_CTL_LOWER_TEMP:
795 case H8_CTL_TEMP_CUTOUT:
796 case H8_CTL_WAKEUP:
797 case H8_CTL_CHG_THRESHOLD:
798 case H8_CTL_TURBO_MODE:
799 case H8_SET_DIAG_STATUS:
800 case H8_SOFTWARE_RESET:
801 case H8_RECAL_PTR:
802 case H8_SET_INT_BATT_PERCENT:
803 case H8_WRT_CFG_INTERFACE_REG:
804 case H8_WRT_EVENT_STATUS_MASK:
805 case H8_ENTER_POST_MODE:
806 case H8_EXIT_POST_MODE:
807 case H8_RD_EEPROM:
808 case H8_WRT_EEPROM:
809 case H8_WRT_TO_STATUS_DISP:
810 printk("H8: Write IO status display command done\n");
811 break;
813 case H8_DEFINE_SPC_CHAR:
814 case H8_DEFINE_TABLE_STRING_ENTRY:
815 case H8_PERFORM_EMU_CMD:
816 case H8_EMU_RD_REG:
817 case H8_EMU_WRT_REG:
818 case H8_EMU_RD_RAM:
819 case H8_EMU_WRT_RAM:
820 case H8_BQ_RD_REG:
821 case H8_BQ_WRT_REG:
822 case H8_PWR_OFF:
823 printk ("H8: misc command completed\n");
824 break;
826 return;
830 * Retrieve the current CPU temperature and case temperature. Provides
831 * the feedback for the thermal control algorithm. Synchcronized via
832 * sleep() for priority so that no other actions in the process will take
833 * place before the data becomes available.
836 h8_get_curr_temp(u_char curr_temp[])
838 u_char buf[H8_MAX_CMD_SIZE];
839 unsigned long flags;
841 memset(buf, 0, H8_MAX_CMD_SIZE);
842 buf[0] = H8_RD_CURR_TEMP;
844 h8_q_cmd(buf, 1, 2);
846 save_flags(flags); cli();
848 while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
849 sleep_on(&h8_sync_wait);
851 restore_flags(flags);
853 h8_sync_channel &= ~H8_RD_CURR_TEMP;
854 curr_temp[0] = xx.byte[0];
855 curr_temp[1] = xx.byte[1];
856 xx.word = 0;
858 if(h8_debug & 0x8)
859 printk("H8: curr CPU temp %d, Sys temp %d\n",
860 curr_temp[0], curr_temp[1]);
861 return 0;
864 static void
865 h8_get_max_temp(void)
867 u_char buf[H8_MAX_CMD_SIZE];
869 buf[0] = H8_RD_MAX_TEMP;
870 h8_q_cmd(buf, 1, 2);
874 * Assigns an upper limit to the value of the H8 thermal interrupt.
875 * As an example setting a value of 115 F here will cause the
876 * interrupt to trigger when the CPU temperature reaches 115 F.
878 static void
879 h8_set_upper_therm_thold(int thold)
881 u_char buf[H8_MAX_CMD_SIZE];
883 /* write 0 to reinitialize interrupt */
884 buf[0] = H8_CTL_UPPER_TEMP;
885 buf[1] = 0x0;
886 buf[2] = 0x0;
887 h8_q_cmd(buf, 3, 1);
889 /* Do it for real */
890 buf[0] = H8_CTL_UPPER_TEMP;
891 buf[1] = 0x0;
892 buf[2] = thold;
893 h8_q_cmd(buf, 3, 1);
896 static void
897 h8_get_upper_therm_thold(void)
899 u_char buf[H8_MAX_CMD_SIZE];
901 buf[0] = H8_CTL_UPPER_TEMP;
902 buf[1] = 0xff;
903 buf[2] = 0;
904 h8_q_cmd(buf, 3, 1);
908 * The external status word contains information on keyboard controller,
909 * power button, changes in external batt status, change in DC state,
910 * docking station, etc. General purpose querying use.
913 h8_get_ext_status(u_char stat_word[])
915 u_char buf[H8_MAX_CMD_SIZE];
916 unsigned long flags;
918 memset(buf, 0, H8_MAX_CMD_SIZE);
919 buf[0] = H8_RD_EXT_STATUS;
921 h8_q_cmd(buf, 1, 2);
923 save_flags(flags); cli();
925 while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
926 sleep_on(&h8_sync_wait);
928 restore_flags(flags);
930 h8_sync_channel &= ~H8_GET_EXT_STATUS;
931 stat_word[0] = xx.byte[0];
932 stat_word[1] = xx.byte[1];
933 xx.word = 0;
935 if(h8_debug & 0x8)
936 printk("H8: curr ext status %x, %x\n",
937 stat_word[0], stat_word[1]);
939 return 0;
943 * Thread attached to task 0 manages thermal/physcial state of Alphabook.
944 * When a condition is detected by the interrupt service routine, the
945 * isr does a wakeup() on h8_monitor_wait. The mask value is then
946 * screened for the appropriate action.
950 h8_monitor_thread(void * unused)
952 u_char curr_temp[2];
955 * Need a logic based safety valve here. During boot when this thread is
956 * started and the thermal interrupt is not yet initialized this logic
957 * checks the temperature and acts accordingly. When this path is acted
958 * upon system boot is painfully slow, however, the priority associated
959 * with overheating is high enough to warrant this action.
961 h8_get_curr_temp(curr_temp);
963 printk("H8: Initial CPU temp: %d\n", curr_temp[0]);
965 if(curr_temp[0] >= h8_uthermal_threshold) {
966 h8_set_event_mask(H8_MANAGE_UTHERM);
967 h8_manage_therm();
968 } else {
970 * Arm the upper thermal limit of the H8 so that any temp in
971 * excess will trigger the thermal control mechanism.
973 h8_set_upper_therm_thold(h8_uthermal_threshold);
976 for(;;) {
977 sleep_on(&h8_monitor_wait);
979 if(h8_debug & 0x2)
980 printk("h8_monitor_thread awakened, mask:%x\n",
981 h8_event_mask);
983 if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
984 h8_manage_therm();
987 #if 0
988 if (h8_event_mask & H8_POWER_BUTTON) {
989 h8_system_down();
993 * If an external DC supply is removed or added make
994 * appropriate CPU speed adjustments.
996 if (h8_event_mask & H8_MANAGE_BATTERY) {
997 h8_run_level_3_manage(H8_RUN);
998 h8_clear_event_mask(H8_MANAGE_BATTERY);
1000 #endif
1005 * Function implements the following policy. When the machine is booted
1006 * the system is set to run at full clock speed. When the upper thermal
1007 * threshold is reached as a result of full clock a damping factor is
1008 * applied to cool off the cpu. The default value is one quarter clock
1009 * (57 Mhz). When as a result of this cooling a temperature lower by
1010 * hmc_uthermal_window is reached, the machine is reset to a higher
1011 * speed, one half clock (115 Mhz). One half clock is maintained until
1012 * the upper thermal threshold is again reached restarting the cycle.
1016 h8_manage_therm(void)
1018 u_char curr_temp[2];
1020 if(h8_event_mask & H8_MANAGE_UTHERM) {
1021 /* Upper thermal interrupt received, need to cool down. */
1022 if(h8_debug & 0x10)
1023 printk("H8: Thermal threshold %d F reached\n",
1024 h8_uthermal_threshold);
1025 h8_set_cpu_speed(h8_udamp);
1026 h8_clear_event_mask(H8_MANAGE_UTHERM);
1027 h8_set_event_mask(H8_MANAGE_LTHERM);
1028 /* Check again in 30 seconds for CPU temperature */
1029 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1030 } else if (h8_event_mask & H8_MANAGE_LTHERM) {
1031 /* See how cool the system has become as a result
1032 of the reduction in speed. */
1033 h8_get_curr_temp(curr_temp);
1034 last_temp = curr_temp[0];
1035 if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
1037 /* System cooling has progressed to a point
1038 that the CPU may be sped up. */
1039 h8_set_upper_therm_thold(h8_uthermal_threshold);
1040 h8_set_cpu_speed(h8_ldamp); /* adjustable */
1041 if(h8_debug & 0x10)
1042 printk("H8: CPU cool, applying cpu_divisor: %d \n",
1043 h8_ldamp);
1044 h8_clear_event_mask(H8_MANAGE_LTHERM);
1046 else /* Not cool enough yet, check again in 30 seconds. */
1047 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1048 } else {
1051 return 0;
1055 * Function conditions the value of global_rpb_counter before
1056 * calling the primitive which causes the actual speed change.
1058 void
1059 h8_set_cpu_speed(int speed_divisor)
1062 #ifdef NOT_YET
1064 * global_rpb_counter is consumed by alpha_delay() in determining just
1065 * how much time to delay. It is necessary that the number of microseconds
1066 * in DELAY(n) be kept consistent over a variety of CPU clock speeds.
1067 * To that end global_rpb_counter is here adjusted.
1070 switch (speed_divisor) {
1071 case 0:
1072 global_rpb_counter = rpb->rpb_counter * 2L;
1073 break;
1074 case 1:
1075 global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
1076 break;
1077 case 3:
1078 global_rpb_counter = rpb->rpb_counter / 2L;
1079 break;
1080 case 4:
1081 global_rpb_counter = rpb->rpb_counter / 4L;
1082 break;
1083 case 5:
1084 global_rpb_counter = rpb->rpb_counter / 8L;
1085 break;
1087 * This case most commonly needed for cpu_speed_divisor
1088 * of 2 which is the value assigned by the firmware.
1090 default:
1091 global_rpb_counter = rpb->rpb_counter;
1092 break;
1094 #endif /* NOT_YET */
1096 if(h8_debug & 0x8)
1097 printk("H8: Setting CPU speed to %d MHz\n",
1098 speed_tab[speed_divisor]);
1100 /* Make the actual speed change */
1101 lca_clock_fiddle(speed_divisor);
1105 * Gets value stored in rpb representing CPU clock speed and adjusts this
1106 * value based on the current clock speed divisor.
1108 u_long
1109 h8_get_cpu_speed(void)
1111 u_long speed = 0;
1112 u_long counter;
1114 #ifdef NOT_YET
1115 counter = rpb->rpb_counter / 1000000L;
1117 switch (alphabook_get_clock()) {
1118 case 0:
1119 speed = counter * 2L;
1120 break;
1121 case 1:
1122 speed = counter * 4L / 3L ;
1123 break;
1124 case 2:
1125 speed = counter;
1126 break;
1127 case 3:
1128 speed = counter / 2L;
1129 break;
1130 case 4:
1131 speed = counter / 4L;
1132 break;
1133 case 5:
1134 speed = counter / 8L;
1135 break;
1136 default:
1137 break;
1139 if(h8_debug & 0x8)
1140 printk("H8: CPU speed current setting: %d MHz\n", speed);
1141 #endif /* NOT_YET */
1142 return speed;
1145 static void
1146 h8_activate_monitor(unsigned long unused)
1148 unsigned long flags;
1150 save_flags(flags); cli();
1151 h8_monitor_timer_active = 0;
1152 restore_flags(flags);
1154 wake_up(&h8_monitor_wait);
1157 static void
1158 h8_start_monitor_timer(unsigned long secs)
1160 unsigned long flags;
1162 if (h8_monitor_timer_active)
1163 return;
1165 save_flags(flags); cli();
1166 h8_monitor_timer_active = 1;
1167 restore_flags(flags);
1169 init_timer(&h8_monitor_timer);
1170 h8_monitor_timer.function = h8_activate_monitor;
1171 h8_monitor_timer.expires = secs * HZ + jiffies;
1172 add_timer(&h8_monitor_timer);
1175 static void h8_set_event_mask(int mask)
1177 unsigned long flags;
1179 save_flags(flags); cli();
1180 h8_event_mask |= mask;
1181 restore_flags(flags);
1184 static void h8_clear_event_mask(int mask)
1186 unsigned long flags;
1188 save_flags(flags); cli();
1189 h8_event_mask &= (~mask);
1190 restore_flags(flags);