?? h8.c
字號:
/* * 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;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -