!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/char/   drwxr-xr-x
Free 318.37 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     h8.c (31.09 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * 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%x\n", 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%x\n",
                stat_reg, data_reg);
        }
        } else {
            Dprintk("h8_intr: bogus interrupt\n");
        }
        break;
    }
    case H8_INTR_MODE: { /* H8_INTR_MODE */
        XDprintk("H8 intr/intr_mode\n");
        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/xmit\n");
        /* If a byte level acknowledgement has been received */
        if (data_reg == H8_BYTE_LEVEL_ACK) {
            XDprintk("H8 intr/xmit BYTE ACK\n");
        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 ACK\n");
        /* 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 command\n");
        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/resync\n");
        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/rcv\n");
        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%x\n", qp->cmdbuf[0]);
        }
        break;
    }
    default: /* default */
        Dprintk("H8 intr/unknown\n");
        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 free\n", h8_irq);
                return -EIO;
        }
        printk(KERN_INFO "H8 at 0x%x IRQ %d\n", 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 queue\n");
                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 buffers\n");
                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 idle\n");
                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 dequeue\n");
                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 command\n");

        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%x\n", intrbuf.word);

        /*
         * Power related items
         */
        if (intrbuf.word & H8_DC_CHANGE) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n");
                /* 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 
off\n");
                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_THRESHOLD\n");
                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_STATUS\n");
                /* read_ext_status */
        }
        if (intrbuf.word & H8_EXT_BATT_STATUS) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n");

        }
        if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n");

        }
        if (intrbuf.word & H8_BATT_CHANGE_OVER) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n");

        }
        if (intrbuf.word & H8_WATCHDOG) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n");
                /* nop */
        }
        if (intrbuf.word & H8_SHUTDOWN) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n");
                /* nop */
        }
        if (intrbuf.word & H8_KEYBOARD) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n");
                /* 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_SWITCH\n");
                /* read_ext_status*/
        }
        if (intrbuf.word & H8_INT_BATT_LOW) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); 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_STATE\n");
                /* nop - happens often */
        }
        if (intrbuf.word & H8_INT_BATT_STATUS) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n");

        }
        if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
                /* nop - happens often */
        }
        if (intrbuf.word & H8_EXT_BATT_LOW) {
        if(h8_debug & 0x4)
            printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n");
                /*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%x\n", 
               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 %d\n",
           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 %d\n",
           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 done\n");
        break;

    case H8_RD_PWR_ON_SECS:
        printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n");
        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 %x\n",
           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%x\n",
               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 done\n");
        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 %d\n",
               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 done\n");
        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 completed\n");
        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 %d\n",
               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,  %x\n",
               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: %d\n", 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:%x\n",
                                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 reached\n",
                   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 MHz\n",
               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 MHz\n", 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;

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0305 ]--