h8.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:31k
- /*
- * Hitachi H8/337 Microcontroller driver
- *
- * The H8 is used to deal with the power and thermal environment
- * of a system.
- *
- * Fixes:
- * June 1999, AV added releasing /proc/driver/h8
- * Feb 2000, Borislav Deianov
- * changed queues to use list.h instead of lists.h
- */
- #include <linux/config.h>
- #include <linux/module.h>
- #include <asm/system.h>
- #include <asm/segment.h>
- #include <asm/io.h>
- #include <linux/types.h>
- #include <linux/stddef.h>
- #include <linux/timer.h>
- #include <linux/fcntl.h>
- #include <linux/linkage.h>
- #include <linux/stat.h>
- #include <linux/proc_fs.h>
- #include <linux/miscdevice.h>
- #include <linux/list.h>
- #include <linux/ioport.h>
- #include <linux/poll.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #define __KERNEL_SYSCALLS__
- #include <asm/unistd.h>
- #include "h8.h"
- #define DEBUG_H8
- #ifdef DEBUG_H8
- #define Dprintk printk
- #else
- #define Dprintk
- #endif
- #define XDprintk if(h8_debug==-1)printk
- /*
- * The h8 device is one of the misc char devices.
- */
- #define H8_MINOR_DEV 140
- /*
- * Forward declarations.
- */
- static int h8_init(void);
- static int h8_display_blank(void);
- static int h8_display_unblank(void);
- static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
- static int h8_get_info(char *, char **, off_t, int);
- /*
- * Support Routines.
- */
- static void h8_hw_init(void);
- static void h8_start_new_cmd(void);
- static void h8_send_next_cmd_byte(void);
- static void h8_read_event_status(void);
- static void h8_sync(void);
- static void h8_q_cmd(u_char *, int, int);
- static void h8_cmd_done(h8_cmd_q_t *qp);
- static int h8_alloc_queues(void);
- static u_long h8_get_cpu_speed(void);
- static int h8_get_curr_temp(u_char curr_temp[]);
- static void h8_get_max_temp(void);
- static void h8_get_upper_therm_thold(void);
- static void h8_set_upper_therm_thold(int);
- static int h8_get_ext_status(u_char stat_word[]);
- static int h8_monitor_thread(void *);
- static int h8_manage_therm(void);
- static void h8_set_cpu_speed(int speed_divisor);
- static void h8_start_monitor_timer(unsigned long secs);
- static void h8_activate_monitor(unsigned long unused);
- /* in arch/alpha/kernel/lca.c */
- extern void lca_clock_print(void);
- extern int lca_get_clock(void);
- extern void lca_clock_fiddle(int);
- static void h8_set_event_mask(int);
- static void h8_clear_event_mask(int);
- /*
- * Driver structures
- */
- static struct timer_list h8_monitor_timer;
- static int h8_monitor_timer_active = 0;
- static char driver_version[] = "X0.0";/* no spaces */
- static union intr_buf intrbuf;
- static int intr_buf_ptr;
- static union intr_buf xx;
- static u_char last_temp;
- /*
- * I/O Macros for register reads and writes.
- */
- #define H8_READ(a) inb((a))
- #define H8_WRITE(d,a) outb((d),(a))
- #define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
- #define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
- #define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
- #define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
- static unsigned int h8_base = H8_BASE_ADDR;
- static unsigned int h8_irq = H8_IRQ;
- static unsigned int h8_state = H8_IDLE;
- static unsigned int h8_index = -1;
- static unsigned int h8_enabled = 0;
- static LIST_HEAD(h8_actq);
- static LIST_HEAD(h8_cmdq);
- static LIST_HEAD(h8_freeq);
- /*
- * Globals used in thermal control of Alphabook1.
- */
- static int cpu_speed_divisor = -1;
- static int h8_event_mask = 0;
- static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
- static unsigned int h8_command_mask = 0;
- static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
- static int h8_uthermal_window = UTH_HYSTERESIS;
- static int h8_debug = 0xfffffdfc;
- static int h8_ldamp = MHZ_115;
- static int h8_udamp = MHZ_57;
- static u_char h8_current_temp = 0;
- static u_char h8_system_temp = 0;
- static int h8_sync_channel = 0;
- static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
- static int h8_init_performed;
- /* CPU speeds and clock divisor values */
- static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
-
- /*
- * H8 interrupt handler
- */
- static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
- {
- u_char stat_reg, data_reg;
- h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
- stat_reg = H8_GET_STATUS;
- data_reg = H8_READ_DATA;
- XDprintk("h8_intr: state %d status 0x%x data 0x%xn", h8_state, stat_reg, data_reg);
- switch (h8_state) {
- /* Response to an asynchronous event. */
- case H8_IDLE: { /* H8_IDLE */
- if (stat_reg & H8_OFULL) {
- if (data_reg == H8_INTR) {
- h8_state = H8_INTR_MODE;
- /* Executing a command to determine what happened. */
- WRITE_CMD(H8_RD_EVENT_STATUS);
- intr_buf_ptr = 1;
- WRITE_CMD(H8_RD_EVENT_STATUS);
- } else {
- Dprintk("h8_intr: idle stat 0x%x data 0x%xn",
- stat_reg, data_reg);
- }
- } else {
- Dprintk("h8_intr: bogus interruptn");
- }
- break;
- }
- case H8_INTR_MODE: { /* H8_INTR_MODE */
- XDprintk("H8 intr/intr_moden");
- if (data_reg == H8_BYTE_LEVEL_ACK) {
- return;
- } else if (data_reg == H8_CMD_ACK) {
- return;
- } else {
- intrbuf.byte[intr_buf_ptr] = data_reg;
- if(!intr_buf_ptr) {
- h8_state = H8_IDLE;
- h8_read_event_status();
- }
- intr_buf_ptr--;
- }
- break;
- }
- /* Placed in this state by h8_start_new_cmd(). */
- case H8_XMIT: { /* H8_XMIT */
- XDprintk("H8 intr/xmitn");
- /* If a byte level acknowledgement has been received */
- if (data_reg == H8_BYTE_LEVEL_ACK) {
- XDprintk("H8 intr/xmit BYTE ACKn");
- qp->nacks++;
- if (qp->nacks > qp->ncmd)
- if(h8_debug & 0x1)
- Dprintk("h8intr: bogus # of acks!n");
- /*
- * If the number of bytes sent is less than the total
- * number of bytes in the command.
- */
- if (qp->cnt < qp->ncmd) {
- h8_send_next_cmd_byte();
- }
- return;
- /* If the complete command has produced an acknowledgement. */
- } else if (data_reg == H8_CMD_ACK) {
- XDprintk("H8 intr/xmit CMD ACKn");
- /* If there are response bytes */
- if (qp->nrsp)
- h8_state = H8_RCV;
- else
- h8_state = H8_IDLE;
- qp->cnt = 0;
- return;
- /* Error, need to start over with a clean slate. */
- } else if (data_reg == H8_NACK) {
- XDprintk("h8_intr: NACK received restarting commandn");
- qp->nacks = 0;
- qp->cnt = 0;
- h8_state = H8_IDLE;
- WRITE_CMD(H8_SYNC);
- return;
- } else {
- Dprintk ("h8intr: xmit unknown data 0x%x n", data_reg);
- return;
- }
- break;
- }
- case H8_RESYNC: { /* H8_RESYNC */
- XDprintk("H8 intr/resyncn");
- if (data_reg == H8_BYTE_LEVEL_ACK) {
- return;
- } else if (data_reg == H8_SYNC_BYTE) {
- h8_state = H8_IDLE;
- if (!list_empty(&h8_actq))
- h8_send_next_cmd_byte();
- } else {
- Dprintk ("h8_intr: resync unknown data 0x%x n", data_reg);
- return;
- }
- break;
- }
- case H8_RCV: { /* H8_RCV */
- XDprintk("H8 intr/rcvn");
- if (qp->cnt < qp->nrsp) {
- qp->rcvbuf[qp->cnt] = data_reg;
- qp->cnt++;
- /* If command reception finished. */
- if (qp->cnt == qp->nrsp) {
- h8_state = H8_IDLE;
- list_del(&qp->link);
- h8_cmd_done (qp);
- /* More commands to send over? */
- if (!list_empty(&h8_cmdq))
- h8_start_new_cmd();
- }
- return;
- } else {
- Dprintk ("h8intr: rcv overflow cmd 0x%xn", qp->cmdbuf[0]);
- }
- break;
- }
- default: /* default */
- Dprintk("H8 intr/unknownn");
- break;
- }
- return;
- }
- static void __exit h8_cleanup (void)
- {
- remove_proc_entry("driver/h8", NULL);
- release_region(h8_base, 8);
- free_irq(h8_irq, NULL);
- }
- static int __init h8_init(void)
- {
- if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
- {
- printk(KERN_ERR "H8: error: IRQ %d is not freen", h8_irq);
- return -EIO;
- }
- printk(KERN_INFO "H8 at 0x%x IRQ %dn", h8_base, h8_irq);
- create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
- request_region(h8_base, 8, "h8");
- h8_alloc_queues();
- h8_hw_init();
- kernel_thread(h8_monitor_thread, NULL, 0);
- return 0;
- }
- module_init(h8_init);
- module_exit(h8_cleanup);
- static void __init h8_hw_init(void)
- {
- u_char buf[H8_MAX_CMD_SIZE];
- /* set CPU speed to max for booting */
- h8_set_cpu_speed(MHZ_230);
- /*
- * Initialize the H8
- */
- h8_sync(); /* activate interrupts */
- /* To clear conditions left by console */
- h8_read_event_status();
- /* Perform a conditioning read */
- buf[0] = H8_DEVICE_CONTROL;
- buf[1] = 0xff;
- buf[2] = 0x0;
- h8_q_cmd(buf, 3, 1);
- /* Turn on built-in and external mice, capture power switch */
- buf[0] = H8_DEVICE_CONTROL;
- buf[1] = 0x0;
- buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
- /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
- h8_q_cmd(buf, 3, 1);
- h8_enabled = 1;
- return;
- }
- static int h8_get_info(char *buf, char **start, off_t fpos, int length)
- {
- #ifdef CONFIG_PROC_FS
- char *p;
- if (!h8_enabled)
- return 0;
- p = buf;
- /*
- 0) Linux driver version (this will change if format changes)
- 1)
- 2)
- 3)
- 4)
- */
-
- p += sprintf(p, "%s n",
- driver_version
- );
- return p - buf;
- #else
- return 0;
- #endif
- }
- /* Called from console driver -- must make sure h8_enabled. */
- static int h8_display_blank(void)
- {
- #ifdef CONFIG_H8_DISPLAY_BLANK
- int error;
- if (!h8_enabled)
- return 0;
- error = h8_set_display_power_state(H8_STATE_STANDBY);
- if (error == H8_SUCCESS)
- return 1;
- h8_error("set display standby", error);
- #endif
- return 0;
- }
- /* Called from console driver -- must make sure h8_enabled. */
- static int h8_display_unblank(void)
- {
- #ifdef CONFIG_H8_DISPLAY_BLANK
- int error;
- if (!h8_enabled)
- return 0;
- error = h8_set_display_power_state(H8_STATE_READY);
- if (error == H8_SUCCESS)
- return 1;
- h8_error("set display ready", error);
- #endif
- return 0;
- }
- static int h8_alloc_queues(void)
- {
- h8_cmd_q_t *qp;
- unsigned long flags;
- int i;
- qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
- GFP_KERNEL);
- if (!qp) {
- printk(KERN_ERR "H8: could not allocate memory for command queuen");
- return(0);
- }
- /* add to the free queue */
- save_flags(flags); cli();
- for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
- /* place each at front of freeq */
- list_add(&qp[i].link, &h8_freeq);
- }
- restore_flags(flags);
- return (1);
- }
- /*
- * Basic means by which commands are sent to the H8.
- */
- void
- h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
- {
- h8_cmd_q_t *qp;
- unsigned long flags;
- int i;
- /* get cmd buf */
- save_flags(flags); cli();
- while (list_empty(&h8_freeq)) {
- Dprintk("H8: need to allocate more cmd buffersn");
- restore_flags(flags);
- h8_alloc_queues();
- save_flags(flags); cli();
- }
- /* get first element from queue */
- qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
- list_del(&qp->link);
- restore_flags(flags);
- /* fill it in */
- for (i = 0; i < cmd_size; i++)
- qp->cmdbuf[i] = cmd[i];
- qp->ncmd = cmd_size;
- qp->nrsp = resp_size;
- /* queue it at the end of the cmd queue */
- save_flags(flags); cli();
- /* XXX this actually puts it at the start of cmd queue, bug? */
- list_add(&qp->link, &h8_cmdq);
- restore_flags(flags);
- h8_start_new_cmd();
- }
- void
- h8_start_new_cmd(void)
- {
- unsigned long flags;
- h8_cmd_q_t *qp;
- save_flags(flags); cli();
- if (h8_state != H8_IDLE) {
- if (h8_debug & 0x1)
- Dprintk("h8_start_new_cmd: not idlen");
- restore_flags(flags);
- return;
- }
- if (!list_empty(&h8_actq)) {
- Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!n");
- restore_flags(flags);
- return;
- }
- if (list_empty(&h8_cmdq)) {
- Dprintk("h8_start_new_cmd: no command to dequeuen");
- restore_flags(flags);
- return;
- }
- /*
- * Take first command off of the command queue and put
- * it on the active queue.
- */
- qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
- list_del(&qp->link);
- /* XXX should this go to the end of the active queue? */
- list_add(&qp->link, &h8_actq);
- h8_state = H8_XMIT;
- if (h8_debug & 0x1)
- Dprintk("h8_start_new_cmd: Starting a commandn");
- qp->cnt = 1;
- WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */
- restore_flags(flags);
- return;
- }
- void
- h8_send_next_cmd_byte(void)
- {
- h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
- int cnt;
- cnt = qp->cnt;
- qp->cnt++;
- if (h8_debug & 0x1)
- Dprintk("h8 sending next cmd byte 0x%x (0x%x)n",
- cnt, qp->cmdbuf[cnt]);
- if (cnt) {
- WRITE_DATA(qp->cmdbuf[cnt]);
- } else {
- WRITE_CMD(qp->cmdbuf[cnt]);
- }
- return;
- }
- /*
- * Synchronize H8 communications channel for command transmission.
- */
- void
- h8_sync(void)
- {
- u_char buf[H8_MAX_CMD_SIZE];
- buf[0] = H8_SYNC;
- buf[1] = H8_SYNC_BYTE;
- h8_q_cmd(buf, 2, 1);
- }
- /*
- * Responds to external interrupt. Reads event status word and
- * decodes type of interrupt.
- */
- void
- h8_read_event_status(void)
- {
- if(h8_debug & 0x200)
- printk(KERN_DEBUG "h8_read_event_status: value 0x%xn", intrbuf.word);
- /*
- * Power related items
- */
- if (intrbuf.word & H8_DC_CHANGE) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: DC_CHANGEn");
- /* see if dc added or removed, set batt/dc flag, send event */
- h8_set_event_mask(H8_MANAGE_BATTERY);
- wake_up(&h8_monitor_wait);
- }
- if (intrbuf.word & H8_POWER_BUTTON) {
- printk(KERN_CRIT "Power switch pressed - please wait - preparing to power
- offn");
- h8_set_event_mask(H8_POWER_BUTTON);
- wake_up(&h8_monitor_wait);
- }
- /*
- * Thermal related items
- */
- if (intrbuf.word & H8_THERMAL_THRESHOLD) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLDn");
- h8_set_event_mask(H8_MANAGE_UTHERM);
- wake_up(&h8_monitor_wait);
- }
- /*
- * nops -for now
- */
- if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUSn");
- /* read_ext_status */
- }
- if (intrbuf.word & H8_EXT_BATT_STATUS) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUSn");
- }
- if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATEn");
- }
- if (intrbuf.word & H8_BATT_CHANGE_OVER) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVERn");
- }
- if (intrbuf.word & H8_WATCHDOG) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: WATCHDOGn");
- /* nop */
- }
- if (intrbuf.word & H8_SHUTDOWN) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: SHUTDOWNn");
- /* nop */
- }
- if (intrbuf.word & H8_KEYBOARD) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: KEYBOARDn");
- /* nop */
- }
- if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCHn");
- /* read_ext_status*/
- }
- if (intrbuf.word & H8_INT_BATT_LOW) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOWn"); post
- /* event, warn user */
- }
- if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATEn");
- /* nop - happens often */
- }
- if (intrbuf.word & H8_INT_BATT_STATUS) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUSn");
- }
- if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLDn");
- /* nop - happens often */
- }
- if (intrbuf.word & H8_EXT_BATT_LOW) {
- if(h8_debug & 0x4)
- printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOWn");
- /*if no internal, post event, warn user */
- /* else nop */
- }
- return;
- }
- /*
- * Function called when H8 has performed requested command.
- */
- static void
- h8_cmd_done(h8_cmd_q_t *qp)
- {
- /* what to do */
- switch (qp->cmdbuf[0]) {
- case H8_SYNC:
- if (h8_debug & 0x40000)
- printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%xn",
- qp->rcvbuf[0]);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_SN:
- case H8_RD_ENET_ADDR:
- printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x n",
- qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
- qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_HW_VER:
- case H8_RD_MIC_VER:
- case H8_RD_MAX_TEMP:
- printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %dn",
- qp->rcvbuf[0], qp->rcvbuf[1]);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_MIN_TEMP:
- printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %dn",
- qp->rcvbuf[0], qp->rcvbuf[1]);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_CURR_TEMP:
- h8_sync_channel |= H8_RD_CURR_TEMP;
- xx.byte[0] = qp->rcvbuf[0];
- xx.byte[1] = qp->rcvbuf[1];
- wake_up(&h8_sync_wait);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_SYS_VARIENT:
- case H8_RD_PWR_ON_CYCLES:
- printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command donen");
- break;
- case H8_RD_PWR_ON_SECS:
- printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command donen");
- break;
- case H8_RD_RESET_STATUS:
- case H8_RD_PWR_DN_STATUS:
- case H8_RD_EVENT_STATUS:
- case H8_RD_ROM_CKSM:
- case H8_RD_EXT_STATUS:
- xx.byte[1] = qp->rcvbuf[0];
- xx.byte[0] = qp->rcvbuf[1];
- h8_sync_channel |= H8_GET_EXT_STATUS;
- wake_up(&h8_sync_wait);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_USER_CFG:
- case H8_RD_INT_BATT_VOLT:
- case H8_RD_DC_INPUT_VOLT:
- case H8_RD_HORIZ_PTR_VOLT:
- case H8_RD_VERT_PTR_VOLT:
- case H8_RD_EEPROM_STATUS:
- case H8_RD_ERR_STATUS:
- case H8_RD_NEW_BUSY_SPEED:
- case H8_RD_CONFIG_INTERFACE:
- case H8_RD_INT_BATT_STATUS:
- printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %xn",
- qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_RD_EXT_BATT_STATUS:
- case H8_RD_PWR_UP_STATUS:
- case H8_RD_EVENT_STATUS_MASK:
- case H8_CTL_EMU_BITPORT:
- case H8_DEVICE_CONTROL:
- if(h8_debug & 0x20000) {
- printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%xn",
- qp->rcvbuf[0]);
- }
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_CTL_TFT_BRT_DC:
- case H8_CTL_WATCHDOG:
- case H8_CTL_MIC_PROT:
- case H8_CTL_INT_BATT_CHG:
- case H8_CTL_EXT_BATT_CHG:
- case H8_CTL_MARK_SPACE:
- case H8_CTL_MOUSE_SENSITIVITY:
- case H8_CTL_DIAG_MODE:
- case H8_CTL_IDLE_AND_BUSY_SPDS:
- printk(KERN_DEBUG "H8: Idle and busy speed command donen");
- break;
- case H8_CTL_TFT_BRT_BATT:
- case H8_CTL_UPPER_TEMP:
- if(h8_debug & 0x10) {
- XDprintk("H8: ctl upper thermal thresh cmd done - returned was %dn",
- qp->rcvbuf[0]);
- }
- list_add(&qp->link, &h8_freeq);
- break;
- case H8_CTL_LOWER_TEMP:
- case H8_CTL_TEMP_CUTOUT:
- case H8_CTL_WAKEUP:
- case H8_CTL_CHG_THRESHOLD:
- case H8_CTL_TURBO_MODE:
- case H8_SET_DIAG_STATUS:
- case H8_SOFTWARE_RESET:
- case H8_RECAL_PTR:
- case H8_SET_INT_BATT_PERCENT:
- case H8_WRT_CFG_INTERFACE_REG:
- case H8_WRT_EVENT_STATUS_MASK:
- case H8_ENTER_POST_MODE:
- case H8_EXIT_POST_MODE:
- case H8_RD_EEPROM:
- case H8_WRT_EEPROM:
- case H8_WRT_TO_STATUS_DISP:
- printk("H8: Write IO status display command donen");
- break;
- case H8_DEFINE_SPC_CHAR:
- case H8_DEFINE_TABLE_STRING_ENTRY:
- case H8_PERFORM_EMU_CMD:
- case H8_EMU_RD_REG:
- case H8_EMU_WRT_REG:
- case H8_EMU_RD_RAM:
- case H8_EMU_WRT_RAM:
- case H8_BQ_RD_REG:
- case H8_BQ_WRT_REG:
- case H8_PWR_OFF:
- printk (KERN_DEBUG "H8: misc command completedn");
- break;
- }
- return;
- }
- /*
- * Retrieve the current CPU temperature and case temperature. Provides
- * the feedback for the thermal control algorithm. Synchcronized via
- * sleep() for priority so that no other actions in the process will take
- * place before the data becomes available.
- */
- int
- h8_get_curr_temp(u_char curr_temp[])
- {
- u_char buf[H8_MAX_CMD_SIZE];
- unsigned long flags;
- memset(buf, 0, H8_MAX_CMD_SIZE);
- buf[0] = H8_RD_CURR_TEMP;
- h8_q_cmd(buf, 1, 2);
- save_flags(flags); cli();
- while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
- sleep_on(&h8_sync_wait);
- restore_flags(flags);
- h8_sync_channel &= ~H8_RD_CURR_TEMP;
- curr_temp[0] = xx.byte[0];
- curr_temp[1] = xx.byte[1];
- xx.word = 0;
- if(h8_debug & 0x8)
- printk("H8: curr CPU temp %d, Sys temp %dn",
- curr_temp[0], curr_temp[1]);
- return 0;
- }
- static void
- h8_get_max_temp(void)
- {
- u_char buf[H8_MAX_CMD_SIZE];
- buf[0] = H8_RD_MAX_TEMP;
- h8_q_cmd(buf, 1, 2);
- }
- /*
- * Assigns an upper limit to the value of the H8 thermal interrupt.
- * As an example setting a value of 115 F here will cause the
- * interrupt to trigger when the CPU temperature reaches 115 F.
- */
- static void
- h8_set_upper_therm_thold(int thold)
- {
- u_char buf[H8_MAX_CMD_SIZE];
- /* write 0 to reinitialize interrupt */
- buf[0] = H8_CTL_UPPER_TEMP;
- buf[1] = 0x0;
- buf[2] = 0x0;
- h8_q_cmd(buf, 3, 1);
- /* Do it for real */
- buf[0] = H8_CTL_UPPER_TEMP;
- buf[1] = 0x0;
- buf[2] = thold;
- h8_q_cmd(buf, 3, 1);
- }
- static void
- h8_get_upper_therm_thold(void)
- {
- u_char buf[H8_MAX_CMD_SIZE];
- buf[0] = H8_CTL_UPPER_TEMP;
- buf[1] = 0xff;
- buf[2] = 0;
- h8_q_cmd(buf, 3, 1);
- }
- /*
- * The external status word contains information on keyboard controller,
- * power button, changes in external batt status, change in DC state,
- * docking station, etc. General purpose querying use.
- */
- int
- h8_get_ext_status(u_char stat_word[])
- {
- u_char buf[H8_MAX_CMD_SIZE];
- unsigned long flags;
- memset(buf, 0, H8_MAX_CMD_SIZE);
- buf[0] = H8_RD_EXT_STATUS;
- h8_q_cmd(buf, 1, 2);
- save_flags(flags); cli();
- while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
- sleep_on(&h8_sync_wait);
- restore_flags(flags);
- h8_sync_channel &= ~H8_GET_EXT_STATUS;
- stat_word[0] = xx.byte[0];
- stat_word[1] = xx.byte[1];
- xx.word = 0;
- if(h8_debug & 0x8)
- printk("H8: curr ext status %x, %xn",
- stat_word[0], stat_word[1]);
- return 0;
- }
- /*
- * Thread attached to task 0 manages thermal/physcial state of Alphabook.
- * When a condition is detected by the interrupt service routine, the
- * isr does a wakeup() on h8_monitor_wait. The mask value is then
- * screened for the appropriate action.
- */
- int
- h8_monitor_thread(void * unused)
- {
- u_char curr_temp[2];
- /*
- * Need a logic based safety valve here. During boot when this thread is
- * started and the thermal interrupt is not yet initialized this logic
- * checks the temperature and acts accordingly. When this path is acted
- * upon system boot is painfully slow, however, the priority associated
- * with overheating is high enough to warrant this action.
- */
- h8_get_curr_temp(curr_temp);
- printk(KERN_INFO "H8: Initial CPU temp: %dn", curr_temp[0]);
- if(curr_temp[0] >= h8_uthermal_threshold) {
- h8_set_event_mask(H8_MANAGE_UTHERM);
- h8_manage_therm();
- } else {
- /*
- * Arm the upper thermal limit of the H8 so that any temp in
- * excess will trigger the thermal control mechanism.
- */
- h8_set_upper_therm_thold(h8_uthermal_threshold);
- }
- for(;;) {
- sleep_on(&h8_monitor_wait);
- if(h8_debug & 0x2)
- printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%xn",
- h8_event_mask);
- if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
- h8_manage_therm();
- }
- #if 0
- if (h8_event_mask & H8_POWER_BUTTON) {
- h8_system_down();
- }
- /*
- * If an external DC supply is removed or added make
- * appropriate CPU speed adjustments.
- */
- if (h8_event_mask & H8_MANAGE_BATTERY) {
- h8_run_level_3_manage(H8_RUN);
- h8_clear_event_mask(H8_MANAGE_BATTERY);
- }
- #endif
- }
- }
- /*
- * Function implements the following policy. When the machine is booted
- * the system is set to run at full clock speed. When the upper thermal
- * threshold is reached as a result of full clock a damping factor is
- * applied to cool off the cpu. The default value is one quarter clock
- * (57 Mhz). When as a result of this cooling a temperature lower by
- * hmc_uthermal_window is reached, the machine is reset to a higher
- * speed, one half clock (115 Mhz). One half clock is maintained until
- * the upper thermal threshold is again reached restarting the cycle.
- */
- int
- h8_manage_therm(void)
- {
- u_char curr_temp[2];
- if(h8_event_mask & H8_MANAGE_UTHERM) {
- /* Upper thermal interrupt received, need to cool down. */
- if(h8_debug & 0x10)
- printk(KERN_WARNING "H8: Thermal threshold %d F reachedn",
- h8_uthermal_threshold);
- h8_set_cpu_speed(h8_udamp);
- h8_clear_event_mask(H8_MANAGE_UTHERM);
- h8_set_event_mask(H8_MANAGE_LTHERM);
- /* Check again in 30 seconds for CPU temperature */
- h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
- } else if (h8_event_mask & H8_MANAGE_LTHERM) {
- /* See how cool the system has become as a result
- of the reduction in speed. */
- h8_get_curr_temp(curr_temp);
- last_temp = curr_temp[0];
- if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
- {
- /* System cooling has progressed to a point
- that the CPU may be sped up. */
- h8_set_upper_therm_thold(h8_uthermal_threshold);
- h8_set_cpu_speed(h8_ldamp); /* adjustable */
- if(h8_debug & 0x10)
- printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d n",
- h8_ldamp);
- h8_clear_event_mask(H8_MANAGE_LTHERM);
- }
- else /* Not cool enough yet, check again in 30 seconds. */
- h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
- } else {
-
- }
- return 0;
- }
- /*
- * Function conditions the value of global_rpb_counter before
- * calling the primitive which causes the actual speed change.
- */
- void
- h8_set_cpu_speed(int speed_divisor)
- {
- #ifdef NOT_YET
- /*
- * global_rpb_counter is consumed by alpha_delay() in determining just
- * how much time to delay. It is necessary that the number of microseconds
- * in DELAY(n) be kept consistent over a variety of CPU clock speeds.
- * To that end global_rpb_counter is here adjusted.
- */
-
- switch (speed_divisor) {
- case 0:
- global_rpb_counter = rpb->rpb_counter * 2L;
- break;
- case 1:
- global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
- break;
- case 3:
- global_rpb_counter = rpb->rpb_counter / 2L;
- break;
- case 4:
- global_rpb_counter = rpb->rpb_counter / 4L;
- break;
- case 5:
- global_rpb_counter = rpb->rpb_counter / 8L;
- break;
- /*
- * This case most commonly needed for cpu_speed_divisor
- * of 2 which is the value assigned by the firmware.
- */
- default:
- global_rpb_counter = rpb->rpb_counter;
- break;
- }
- #endif /* NOT_YET */
- if(h8_debug & 0x8)
- printk(KERN_DEBUG "H8: Setting CPU speed to %d MHzn",
- speed_tab[speed_divisor]);
- /* Make the actual speed change */
- lca_clock_fiddle(speed_divisor);
- }
- /*
- * Gets value stored in rpb representing CPU clock speed and adjusts this
- * value based on the current clock speed divisor.
- */
- u_long
- h8_get_cpu_speed(void)
- {
- u_long speed = 0;
- u_long counter;
- #ifdef NOT_YET
- counter = rpb->rpb_counter / 1000000L;
- switch (alphabook_get_clock()) {
- case 0:
- speed = counter * 2L;
- break;
- case 1:
- speed = counter * 4L / 3L ;
- break;
- case 2:
- speed = counter;
- break;
- case 3:
- speed = counter / 2L;
- break;
- case 4:
- speed = counter / 4L;
- break;
- case 5:
- speed = counter / 8L;
- break;
- default:
- break;
- }
- if(h8_debug & 0x8)
- printk(KERN_DEBUG "H8: CPU speed current setting: %d MHzn", speed);
- #endif /* NOT_YET */
- return speed;
- }
- static void
- h8_activate_monitor(unsigned long unused)
- {
- unsigned long flags;
- save_flags(flags); cli();
- h8_monitor_timer_active = 0;
- restore_flags(flags);
- wake_up(&h8_monitor_wait);
- }
- static void
- h8_start_monitor_timer(unsigned long secs)
- {
- unsigned long flags;
- if (h8_monitor_timer_active)
- return;
- save_flags(flags); cli();
- h8_monitor_timer_active = 1;
- restore_flags(flags);
- init_timer(&h8_monitor_timer);
- h8_monitor_timer.function = h8_activate_monitor;
- h8_monitor_timer.expires = secs * HZ + jiffies;
- add_timer(&h8_monitor_timer);
- }
- static void h8_set_event_mask(int mask)
- {
- unsigned long flags;
- save_flags(flags); cli();
- h8_event_mask |= mask;
- restore_flags(flags);
- }
- static void h8_clear_event_mask(int mask)
- {
- unsigned long flags;
- save_flags(flags); cli();
- h8_event_mask &= (~mask);
- restore_flags(flags);
- }
- MODULE_LICENSE("GPL");
- EXPORT_NO_SYMBOLS;