h8.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:31k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Hitachi H8/337 Microcontroller driver
  3.  *
  4.  * The H8 is used to deal with the power and thermal environment
  5.  * of a system.
  6.  *
  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
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/module.h>
  14. #include <asm/system.h>
  15. #include <asm/segment.h>
  16. #include <asm/io.h>
  17. #include <linux/types.h>
  18. #include <linux/stddef.h>
  19. #include <linux/timer.h>
  20. #include <linux/fcntl.h>
  21. #include <linux/linkage.h>
  22. #include <linux/stat.h>
  23. #include <linux/proc_fs.h>
  24. #include <linux/miscdevice.h>
  25. #include <linux/list.h>
  26. #include <linux/ioport.h>
  27. #include <linux/poll.h>
  28. #include <linux/init.h>
  29. #include <linux/slab.h>
  30. #define __KERNEL_SYSCALLS__
  31. #include <asm/unistd.h>
  32. #include "h8.h"
  33. #define DEBUG_H8
  34. #ifdef DEBUG_H8
  35. #define Dprintk printk
  36. #else
  37. #define Dprintk
  38. #endif
  39. #define XDprintk if(h8_debug==-1)printk
  40. /*
  41.  * The h8 device is one of the misc char devices.
  42.  */
  43. #define H8_MINOR_DEV   140
  44. /*
  45.  * Forward declarations.
  46.  */
  47. static int  h8_init(void);
  48. static int  h8_display_blank(void);
  49. static int  h8_display_unblank(void);
  50. static void  h8_intr(int irq, void *dev_id, struct pt_regs *regs);
  51. static int   h8_get_info(char *, char **, off_t, int);
  52. /*
  53.  * Support Routines.
  54.  */
  55. static void h8_hw_init(void);
  56. static void h8_start_new_cmd(void);
  57. static void h8_send_next_cmd_byte(void);
  58. static void h8_read_event_status(void);
  59. static void h8_sync(void);
  60. static void h8_q_cmd(u_char *, int, int);
  61. static void h8_cmd_done(h8_cmd_q_t *qp);
  62. static int  h8_alloc_queues(void);
  63. static u_long h8_get_cpu_speed(void);
  64. static int h8_get_curr_temp(u_char curr_temp[]);
  65. static void h8_get_max_temp(void);
  66. static void h8_get_upper_therm_thold(void);
  67. static void h8_set_upper_therm_thold(int);
  68. static int h8_get_ext_status(u_char stat_word[]);
  69. static int h8_monitor_thread(void *);
  70. static int h8_manage_therm(void);
  71. static void h8_set_cpu_speed(int speed_divisor);
  72. static void h8_start_monitor_timer(unsigned long secs);
  73. static void h8_activate_monitor(unsigned long unused);
  74. /* in arch/alpha/kernel/lca.c */
  75. extern void lca_clock_print(void);
  76. extern int  lca_get_clock(void);
  77. extern void lca_clock_fiddle(int);
  78. static void h8_set_event_mask(int);
  79. static void h8_clear_event_mask(int);
  80. /*
  81.  * Driver structures
  82.  */
  83. static struct timer_list h8_monitor_timer;
  84. static int h8_monitor_timer_active = 0;
  85. static char  driver_version[] = "X0.0";/* no spaces */
  86. static union intr_buf intrbuf;
  87. static int intr_buf_ptr;
  88. static union   intr_buf xx;
  89. static u_char  last_temp;
  90. /*
  91.  * I/O Macros for register reads and writes.
  92.  */
  93. #define H8_READ(a)  inb((a))
  94. #define H8_WRITE(d,a) outb((d),(a))
  95. #define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
  96. #define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
  97. #define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
  98. #define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
  99. static unsigned int h8_base = H8_BASE_ADDR;
  100. static unsigned int h8_irq = H8_IRQ;
  101. static unsigned int h8_state = H8_IDLE;
  102. static unsigned int h8_index = -1;
  103. static unsigned int h8_enabled = 0;
  104. static LIST_HEAD(h8_actq);
  105. static LIST_HEAD(h8_cmdq);
  106. static LIST_HEAD(h8_freeq);
  107. /* 
  108.  * Globals used in thermal control of Alphabook1.
  109.  */
  110. static int cpu_speed_divisor = -1;
  111. static int h8_event_mask = 0;
  112. static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
  113. static unsigned int h8_command_mask = 0;
  114. static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
  115. static int h8_uthermal_window = UTH_HYSTERESIS;       
  116. static int h8_debug = 0xfffffdfc;
  117. static int h8_ldamp = MHZ_115;
  118. static int h8_udamp = MHZ_57;
  119. static u_char h8_current_temp = 0;
  120. static u_char h8_system_temp = 0;
  121. static int h8_sync_channel = 0;
  122. static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
  123. static int h8_init_performed;
  124. /* CPU speeds and clock divisor values */
  125. static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
  126.   
  127. /*
  128.  * H8 interrupt handler
  129.   */
  130. static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
  131. {
  132. u_char stat_reg, data_reg;
  133. h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
  134. stat_reg = H8_GET_STATUS;
  135. data_reg = H8_READ_DATA;
  136. XDprintk("h8_intr: state %d status 0x%x data 0x%xn", h8_state, stat_reg, data_reg);
  137. switch (h8_state) {
  138.   /* Response to an asynchronous event. */
  139. case H8_IDLE: { /* H8_IDLE */
  140.     if (stat_reg & H8_OFULL) {
  141.         if (data_reg == H8_INTR) {
  142.     h8_state = H8_INTR_MODE;
  143.     /* Executing a command to determine what happened. */
  144.     WRITE_CMD(H8_RD_EVENT_STATUS);
  145.     intr_buf_ptr = 1;
  146.     WRITE_CMD(H8_RD_EVENT_STATUS);
  147. } else {
  148.     Dprintk("h8_intr: idle stat 0x%x data 0x%xn",
  149.     stat_reg, data_reg);
  150. }
  151.     } else {
  152.         Dprintk("h8_intr: bogus interruptn");
  153.     }
  154.     break;
  155. }
  156. case H8_INTR_MODE: { /* H8_INTR_MODE */
  157.     XDprintk("H8 intr/intr_moden");
  158.     if (data_reg == H8_BYTE_LEVEL_ACK) {
  159.         return;
  160.     } else if (data_reg == H8_CMD_ACK) {
  161.         return;
  162.     } else {
  163.         intrbuf.byte[intr_buf_ptr] = data_reg;
  164. if(!intr_buf_ptr) {
  165.     h8_state = H8_IDLE;
  166.     h8_read_event_status();
  167. }
  168. intr_buf_ptr--;
  169.     }
  170.     break;
  171. }
  172. /* Placed in this state by h8_start_new_cmd(). */
  173. case H8_XMIT: { /* H8_XMIT */
  174.     XDprintk("H8 intr/xmitn");
  175.     /* If a byte level acknowledgement has been received */
  176.     if (data_reg == H8_BYTE_LEVEL_ACK) {
  177.         XDprintk("H8 intr/xmit BYTE ACKn");
  178. qp->nacks++;
  179. if (qp->nacks > qp->ncmd)
  180.     if(h8_debug & 0x1)
  181.         Dprintk("h8intr: bogus # of acks!n");
  182. /* 
  183.  * If the number of bytes sent is less than the total 
  184.  * number of bytes in the command.
  185.  */ 
  186. if (qp->cnt < qp->ncmd) {
  187.     h8_send_next_cmd_byte();
  188. }
  189. return;
  190. /* If the complete command has produced an acknowledgement. */
  191.     } else if (data_reg == H8_CMD_ACK) {
  192.         XDprintk("H8 intr/xmit CMD ACKn");
  193. /* If there are response bytes */
  194. if (qp->nrsp)
  195.     h8_state = H8_RCV;
  196. else
  197.     h8_state = H8_IDLE;
  198. qp->cnt = 0;
  199. return;
  200. /* Error, need to start over with a clean slate. */
  201.     } else if (data_reg == H8_NACK) {
  202.         XDprintk("h8_intr: NACK received restarting commandn");
  203. qp->nacks = 0;
  204. qp->cnt = 0;
  205. h8_state = H8_IDLE;
  206. WRITE_CMD(H8_SYNC);
  207. return;
  208.     } else {
  209.         Dprintk ("h8intr: xmit unknown data 0x%x n", data_reg);
  210. return;
  211.     }
  212.     break;
  213. }
  214. case H8_RESYNC: { /* H8_RESYNC */
  215.     XDprintk("H8 intr/resyncn");
  216.     if (data_reg == H8_BYTE_LEVEL_ACK) {
  217.         return;
  218.     } else if (data_reg == H8_SYNC_BYTE) {
  219.         h8_state = H8_IDLE;
  220. if (!list_empty(&h8_actq))
  221.     h8_send_next_cmd_byte();
  222.     } else {
  223.         Dprintk ("h8_intr: resync unknown data 0x%x n", data_reg);
  224. return;
  225.     }
  226.     break;
  227. case H8_RCV: { /* H8_RCV */
  228.     XDprintk("H8 intr/rcvn");
  229.     if (qp->cnt < qp->nrsp) {
  230.         qp->rcvbuf[qp->cnt] = data_reg;
  231. qp->cnt++;
  232. /* If command reception finished. */
  233. if (qp->cnt == qp->nrsp) {
  234.     h8_state = H8_IDLE;
  235.     list_del(&qp->link);
  236.     h8_cmd_done (qp);
  237.     /* More commands to send over? */
  238.     if (!list_empty(&h8_cmdq))
  239.         h8_start_new_cmd();
  240. }
  241. return;
  242.     } else {
  243.         Dprintk ("h8intr: rcv overflow cmd 0x%xn", qp->cmdbuf[0]);
  244.     }
  245.     break;
  246. }
  247. default: /* default */
  248.     Dprintk("H8 intr/unknownn");
  249.     break;
  250. }
  251. return;
  252. }
  253. static void __exit h8_cleanup (void)
  254. {
  255. remove_proc_entry("driver/h8", NULL);
  256.         release_region(h8_base, 8);
  257.         free_irq(h8_irq, NULL);
  258. }
  259. static int __init h8_init(void)
  260. {
  261.         if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
  262.         {
  263.                 printk(KERN_ERR "H8: error: IRQ %d is not freen", h8_irq);
  264.                 return -EIO;
  265.         }
  266.         printk(KERN_INFO "H8 at 0x%x IRQ %dn", h8_base, h8_irq);
  267.         create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
  268.         request_region(h8_base, 8, "h8");
  269. h8_alloc_queues();
  270. h8_hw_init();
  271. kernel_thread(h8_monitor_thread, NULL, 0);
  272.         return 0;
  273. }
  274. module_init(h8_init);
  275. module_exit(h8_cleanup);
  276. static void __init h8_hw_init(void)
  277. {
  278. u_char buf[H8_MAX_CMD_SIZE];
  279. /* set CPU speed to max for booting */
  280. h8_set_cpu_speed(MHZ_230);
  281. /*
  282.  * Initialize the H8
  283.  */
  284. h8_sync();  /* activate interrupts */
  285. /* To clear conditions left by console */
  286. h8_read_event_status(); 
  287. /* Perform a conditioning read */
  288. buf[0] = H8_DEVICE_CONTROL;
  289. buf[1] = 0xff;
  290. buf[2] = 0x0;
  291. h8_q_cmd(buf, 3, 1);
  292. /* Turn on built-in and external mice, capture power switch */
  293. buf[0] = H8_DEVICE_CONTROL;
  294. buf[1] = 0x0;
  295. buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
  296.        /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
  297. h8_q_cmd(buf, 3, 1);
  298.         h8_enabled = 1;
  299. return;
  300. }
  301. static int h8_get_info(char *buf, char **start, off_t fpos, int length)
  302. {
  303. #ifdef CONFIG_PROC_FS
  304.         char *p;
  305.         if (!h8_enabled)
  306.                 return 0;
  307.         p = buf;
  308.         /*
  309.            0) Linux driver version (this will change if format changes)
  310.            1) 
  311.            2) 
  312.            3)
  313.            4)
  314. */
  315.             
  316.         p += sprintf(p, "%s n",
  317.                      driver_version
  318.      );
  319.         return p - buf;
  320. #else
  321. return 0;
  322. #endif
  323. }
  324. /* Called from console driver -- must make sure h8_enabled. */
  325. static int h8_display_blank(void)
  326. {
  327. #ifdef CONFIG_H8_DISPLAY_BLANK
  328.         int     error;
  329.         if (!h8_enabled)
  330.                 return 0;
  331.         error = h8_set_display_power_state(H8_STATE_STANDBY);
  332.         if (error == H8_SUCCESS)
  333.                 return 1;
  334.         h8_error("set display standby", error);
  335. #endif
  336.         return 0;
  337. }
  338. /* Called from console driver -- must make sure h8_enabled. */
  339. static int h8_display_unblank(void)
  340. {
  341. #ifdef CONFIG_H8_DISPLAY_BLANK
  342.         int error;
  343.         if (!h8_enabled)
  344.                 return 0;
  345.         error = h8_set_display_power_state(H8_STATE_READY);
  346.         if (error == H8_SUCCESS)
  347.                 return 1;
  348.         h8_error("set display ready", error);
  349. #endif
  350.         return 0;
  351. }
  352. static int h8_alloc_queues(void)
  353. {
  354.         h8_cmd_q_t *qp;
  355. unsigned long flags;
  356.         int i;
  357.         qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
  358.    GFP_KERNEL);
  359.         if (!qp) {
  360.                 printk(KERN_ERR "H8: could not allocate memory for command queuen");
  361.                 return(0);
  362.         }
  363.         /* add to the free queue */
  364.         save_flags(flags); cli();
  365.         for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
  366.                 /* place each at front of freeq */
  367.                 list_add(&qp[i].link, &h8_freeq);
  368.         }
  369.         restore_flags(flags);
  370.         return (1);
  371. }
  372. /* 
  373.  * Basic means by which commands are sent to the H8.
  374.  */
  375. void
  376. h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
  377. {
  378.         h8_cmd_q_t      *qp;
  379. unsigned long flags;
  380.         int             i;
  381.         /* get cmd buf */
  382. save_flags(flags); cli();
  383.         while (list_empty(&h8_freeq)) {
  384.                 Dprintk("H8: need to allocate more cmd buffersn");
  385.                 restore_flags(flags);
  386.                 h8_alloc_queues();
  387.                 save_flags(flags); cli();
  388.         }
  389.         /* get first element from queue */
  390.         qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
  391.         list_del(&qp->link);
  392.         restore_flags(flags);
  393.         /* fill it in */
  394.         for (i = 0; i < cmd_size; i++)
  395.             qp->cmdbuf[i] = cmd[i];
  396.         qp->ncmd = cmd_size;
  397.         qp->nrsp = resp_size;
  398.         /* queue it at the end of the cmd queue */
  399.         save_flags(flags); cli();
  400.         /* XXX this actually puts it at the start of cmd queue, bug? */
  401.         list_add(&qp->link, &h8_cmdq);
  402.         restore_flags(flags);
  403.         h8_start_new_cmd();
  404. }
  405. void
  406. h8_start_new_cmd(void)
  407. {
  408.         unsigned long flags;
  409.         h8_cmd_q_t *qp;
  410. save_flags(flags); cli();
  411.         if (h8_state != H8_IDLE) {
  412.                 if (h8_debug & 0x1)
  413.                         Dprintk("h8_start_new_cmd: not idlen");
  414.                 restore_flags(flags);
  415.                 return;
  416.         }
  417.         if (!list_empty(&h8_actq)) {
  418.                 Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!n");
  419.                 restore_flags(flags);
  420.                 return;
  421.         }
  422.         if (list_empty(&h8_cmdq)) {
  423.                 Dprintk("h8_start_new_cmd: no command to dequeuen");
  424.                 restore_flags(flags);
  425.                 return;
  426.         }
  427.         /*
  428.          * Take first command off of the command queue and put
  429.          * it on the active queue.
  430.          */
  431.         qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
  432.         list_del(&qp->link);
  433.         /* XXX should this go to the end of the active queue? */
  434.         list_add(&qp->link, &h8_actq);
  435.         h8_state = H8_XMIT;
  436.         if (h8_debug & 0x1)
  437.                 Dprintk("h8_start_new_cmd: Starting a commandn");
  438.         qp->cnt = 1;
  439.         WRITE_CMD(qp->cmdbuf[0]);               /* Kick it off */
  440.         restore_flags(flags);
  441.         return;
  442. }
  443. void
  444. h8_send_next_cmd_byte(void)
  445. {
  446.         h8_cmd_q_t      *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
  447.         int cnt;
  448.         cnt = qp->cnt;
  449.         qp->cnt++;
  450.         if (h8_debug & 0x1)
  451.                 Dprintk("h8 sending next cmd byte 0x%x (0x%x)n",
  452. cnt, qp->cmdbuf[cnt]);
  453.         if (cnt) {
  454.                 WRITE_DATA(qp->cmdbuf[cnt]);
  455.         } else {
  456.                 WRITE_CMD(qp->cmdbuf[cnt]);
  457.         }
  458.         return;
  459. }
  460. /*
  461.  * Synchronize H8 communications channel for command transmission.
  462.  */
  463. void
  464. h8_sync(void)
  465. {
  466.         u_char  buf[H8_MAX_CMD_SIZE];
  467.         buf[0] = H8_SYNC;
  468.         buf[1] = H8_SYNC_BYTE;
  469.         h8_q_cmd(buf, 2, 1);
  470. }
  471. /*
  472.  * Responds to external interrupt. Reads event status word and 
  473.  * decodes type of interrupt. 
  474.  */
  475. void
  476. h8_read_event_status(void)
  477. {
  478.         if(h8_debug & 0x200)
  479.                 printk(KERN_DEBUG "h8_read_event_status: value 0x%xn", intrbuf.word);
  480.         /*
  481.          * Power related items
  482.          */
  483.         if (intrbuf.word & H8_DC_CHANGE) {
  484. if(h8_debug & 0x4)
  485.     printk(KERN_DEBUG "h8_read_event_status: DC_CHANGEn");
  486.                 /* see if dc added or removed, set batt/dc flag, send event */
  487.                 h8_set_event_mask(H8_MANAGE_BATTERY);
  488.                 wake_up(&h8_monitor_wait);
  489.         }
  490.         if (intrbuf.word & H8_POWER_BUTTON) {
  491.                 printk(KERN_CRIT "Power switch pressed - please wait - preparing to power 
  492. offn");
  493.                 h8_set_event_mask(H8_POWER_BUTTON);
  494.                 wake_up(&h8_monitor_wait);
  495.         }
  496.         /*
  497.          * Thermal related items
  498.          */
  499.         if (intrbuf.word & H8_THERMAL_THRESHOLD) {
  500. if(h8_debug & 0x4)
  501.     printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLDn");
  502.                 h8_set_event_mask(H8_MANAGE_UTHERM);
  503.                 wake_up(&h8_monitor_wait);
  504.         }
  505.         /*
  506.          * nops -for now
  507.          */
  508.         if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
  509. if(h8_debug & 0x4)
  510.     printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUSn");
  511.                 /* read_ext_status */
  512.         }
  513.         if (intrbuf.word & H8_EXT_BATT_STATUS) {
  514. if(h8_debug & 0x4)
  515.     printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUSn");
  516.         }
  517.         if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
  518. if(h8_debug & 0x4)
  519.     printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATEn");
  520.         }
  521.         if (intrbuf.word & H8_BATT_CHANGE_OVER) {
  522. if(h8_debug & 0x4)
  523.     printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVERn");
  524.         }
  525.         if (intrbuf.word & H8_WATCHDOG) {
  526. if(h8_debug & 0x4)
  527.     printk(KERN_DEBUG "h8_read_event_status: WATCHDOGn");
  528.                 /* nop */
  529.         }
  530.         if (intrbuf.word & H8_SHUTDOWN) {
  531. if(h8_debug & 0x4)
  532.     printk(KERN_DEBUG "h8_read_event_status: SHUTDOWNn");
  533.                 /* nop */
  534.         }
  535.         if (intrbuf.word & H8_KEYBOARD) {
  536. if(h8_debug & 0x4)
  537.     printk(KERN_DEBUG "h8_read_event_status: KEYBOARDn");
  538.                 /* nop */
  539.         }
  540.         if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
  541. if(h8_debug & 0x4)
  542.     printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCHn");
  543.                 /* read_ext_status*/
  544.         }
  545.         if (intrbuf.word & H8_INT_BATT_LOW) {
  546. if(h8_debug & 0x4)
  547.     printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOWn"); post
  548.                 /* event, warn user */
  549.         }
  550.         if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
  551. if(h8_debug & 0x4)
  552.     printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATEn");
  553.                 /* nop - happens often */
  554.         }
  555.         if (intrbuf.word & H8_INT_BATT_STATUS) {
  556. if(h8_debug & 0x4)
  557.     printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUSn");
  558.         }
  559.         if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
  560. if(h8_debug & 0x4)
  561.     printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLDn");
  562.                 /* nop - happens often */
  563.         }
  564.         if (intrbuf.word & H8_EXT_BATT_LOW) {
  565. if(h8_debug & 0x4)
  566.     printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOWn");
  567.                 /*if no internal, post event, warn user */
  568.                 /* else nop */
  569.         }
  570.         return;
  571. }
  572. /*
  573.  * Function called when H8 has performed requested command.
  574.  */
  575. static void
  576. h8_cmd_done(h8_cmd_q_t *qp)
  577. {
  578.         /* what to do */
  579.         switch (qp->cmdbuf[0]) {
  580. case H8_SYNC:
  581.     if (h8_debug & 0x40000) 
  582.         printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%xn", 
  583.        qp->rcvbuf[0]);
  584.     list_add(&qp->link, &h8_freeq);
  585.     break;
  586. case H8_RD_SN:
  587. case H8_RD_ENET_ADDR:
  588.     printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x n", 
  589.    qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
  590.    qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
  591.     list_add(&qp->link, &h8_freeq);
  592.     break;
  593. case H8_RD_HW_VER:
  594. case H8_RD_MIC_VER:
  595. case H8_RD_MAX_TEMP:
  596.     printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %dn",
  597.    qp->rcvbuf[0], qp->rcvbuf[1]);
  598.     list_add(&qp->link, &h8_freeq);
  599.     break;
  600. case H8_RD_MIN_TEMP:
  601.     printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %dn",
  602.    qp->rcvbuf[0], qp->rcvbuf[1]);
  603.     list_add(&qp->link, &h8_freeq);
  604.     break;
  605. case H8_RD_CURR_TEMP:
  606.     h8_sync_channel |= H8_RD_CURR_TEMP;
  607.     xx.byte[0] = qp->rcvbuf[0];
  608.     xx.byte[1] = qp->rcvbuf[1];
  609.     wake_up(&h8_sync_wait); 
  610.     list_add(&qp->link, &h8_freeq);
  611.     break;
  612. case H8_RD_SYS_VARIENT:
  613. case H8_RD_PWR_ON_CYCLES:
  614.     printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command donen");
  615.     break;
  616. case H8_RD_PWR_ON_SECS:
  617.     printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command donen");
  618.     break;
  619. case H8_RD_RESET_STATUS:
  620. case H8_RD_PWR_DN_STATUS:
  621. case H8_RD_EVENT_STATUS:
  622. case H8_RD_ROM_CKSM:
  623. case H8_RD_EXT_STATUS:
  624.     xx.byte[1] = qp->rcvbuf[0];
  625.     xx.byte[0] = qp->rcvbuf[1];
  626.     h8_sync_channel |= H8_GET_EXT_STATUS;
  627.     wake_up(&h8_sync_wait); 
  628.     list_add(&qp->link, &h8_freeq);
  629.     break;
  630. case H8_RD_USER_CFG:
  631. case H8_RD_INT_BATT_VOLT:
  632. case H8_RD_DC_INPUT_VOLT:
  633. case H8_RD_HORIZ_PTR_VOLT:
  634. case H8_RD_VERT_PTR_VOLT:
  635. case H8_RD_EEPROM_STATUS:
  636. case H8_RD_ERR_STATUS:
  637. case H8_RD_NEW_BUSY_SPEED:
  638. case H8_RD_CONFIG_INTERFACE:
  639. case H8_RD_INT_BATT_STATUS:
  640.     printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %xn",
  641.    qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
  642.     list_add(&qp->link, &h8_freeq);
  643.     break;
  644. case H8_RD_EXT_BATT_STATUS:
  645. case H8_RD_PWR_UP_STATUS:
  646. case H8_RD_EVENT_STATUS_MASK:
  647. case H8_CTL_EMU_BITPORT:
  648. case H8_DEVICE_CONTROL:
  649.     if(h8_debug & 0x20000) {
  650.         printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%xn",
  651.        qp->rcvbuf[0]);
  652.     }
  653.     list_add(&qp->link, &h8_freeq);
  654.     break;
  655. case H8_CTL_TFT_BRT_DC:
  656. case H8_CTL_WATCHDOG:
  657. case H8_CTL_MIC_PROT:
  658. case H8_CTL_INT_BATT_CHG:
  659. case H8_CTL_EXT_BATT_CHG:
  660. case H8_CTL_MARK_SPACE:
  661. case H8_CTL_MOUSE_SENSITIVITY:
  662. case H8_CTL_DIAG_MODE:
  663. case H8_CTL_IDLE_AND_BUSY_SPDS:
  664.     printk(KERN_DEBUG "H8: Idle and busy speed command donen");
  665.     break;
  666. case H8_CTL_TFT_BRT_BATT:
  667. case H8_CTL_UPPER_TEMP:
  668.     if(h8_debug & 0x10) {
  669.         XDprintk("H8: ctl upper thermal thresh cmd done - returned was %dn",
  670.        qp->rcvbuf[0]);
  671.     }
  672.     list_add(&qp->link, &h8_freeq);
  673.     break;
  674. case H8_CTL_LOWER_TEMP:
  675. case H8_CTL_TEMP_CUTOUT:
  676. case H8_CTL_WAKEUP:
  677. case H8_CTL_CHG_THRESHOLD:
  678. case H8_CTL_TURBO_MODE:
  679. case H8_SET_DIAG_STATUS:
  680. case H8_SOFTWARE_RESET:
  681. case H8_RECAL_PTR:
  682. case H8_SET_INT_BATT_PERCENT:
  683. case H8_WRT_CFG_INTERFACE_REG:
  684. case H8_WRT_EVENT_STATUS_MASK:
  685. case H8_ENTER_POST_MODE:
  686. case H8_EXIT_POST_MODE:
  687. case H8_RD_EEPROM:
  688. case H8_WRT_EEPROM:
  689. case H8_WRT_TO_STATUS_DISP:
  690.     printk("H8: Write IO status display command donen");
  691.     break;
  692. case H8_DEFINE_SPC_CHAR:
  693. case H8_DEFINE_TABLE_STRING_ENTRY:
  694. case H8_PERFORM_EMU_CMD:
  695. case H8_EMU_RD_REG:
  696. case H8_EMU_WRT_REG:
  697. case H8_EMU_RD_RAM:
  698. case H8_EMU_WRT_RAM:
  699. case H8_BQ_RD_REG:
  700. case H8_BQ_WRT_REG:
  701. case H8_PWR_OFF:
  702.     printk (KERN_DEBUG "H8: misc command completedn");
  703.     break;
  704.         }
  705.         return;
  706. }
  707. /*
  708.  * Retrieve the current CPU temperature and case temperature.  Provides
  709.  * the feedback for the thermal control algorithm.  Synchcronized via 
  710.  * sleep() for priority so that no other actions in the process will take
  711.  * place before the data becomes available.
  712.  */
  713. int
  714. h8_get_curr_temp(u_char curr_temp[])
  715. {
  716.         u_char  buf[H8_MAX_CMD_SIZE];
  717.         unsigned long flags;
  718.         memset(buf, 0, H8_MAX_CMD_SIZE); 
  719.         buf[0] = H8_RD_CURR_TEMP;
  720.         h8_q_cmd(buf, 1, 2);
  721. save_flags(flags); cli();
  722.         while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
  723.                 sleep_on(&h8_sync_wait); 
  724.         restore_flags(flags);
  725.         h8_sync_channel &= ~H8_RD_CURR_TEMP;
  726.         curr_temp[0] = xx.byte[0];
  727.         curr_temp[1] = xx.byte[1];
  728.         xx.word = 0;
  729.         if(h8_debug & 0x8) 
  730.                 printk("H8: curr CPU temp %d, Sys temp %dn",
  731.        curr_temp[0], curr_temp[1]);
  732.         return 0;
  733. }
  734. static void
  735. h8_get_max_temp(void)
  736. {
  737.         u_char  buf[H8_MAX_CMD_SIZE];
  738.         buf[0] = H8_RD_MAX_TEMP;
  739.         h8_q_cmd(buf, 1, 2);
  740. }
  741. /*
  742.  * Assigns an upper limit to the value of the H8 thermal interrupt.
  743.  * As an example setting a value of 115 F here will cause the 
  744.  * interrupt to trigger when the CPU temperature reaches 115 F.
  745.  */
  746. static void
  747. h8_set_upper_therm_thold(int thold)
  748. {
  749.         u_char  buf[H8_MAX_CMD_SIZE];
  750.         /* write 0 to reinitialize interrupt */
  751.         buf[0] = H8_CTL_UPPER_TEMP;
  752.         buf[1] = 0x0;
  753.         buf[2] = 0x0;
  754.         h8_q_cmd(buf, 3, 1); 
  755.         /* Do it for real */
  756.         buf[0] = H8_CTL_UPPER_TEMP;
  757.         buf[1] = 0x0;
  758.         buf[2] = thold;
  759.         h8_q_cmd(buf, 3, 1); 
  760. }
  761. static void
  762. h8_get_upper_therm_thold(void)
  763. {
  764.         u_char  buf[H8_MAX_CMD_SIZE];
  765.         buf[0] = H8_CTL_UPPER_TEMP;
  766.         buf[1] = 0xff;
  767.         buf[2] = 0;
  768.         h8_q_cmd(buf, 3, 1); 
  769. }
  770. /*
  771.  * The external status word contains information on keyboard controller,
  772.  * power button, changes in external batt status, change in DC state,
  773.  * docking station, etc. General purpose querying use.
  774.  */
  775. int
  776. h8_get_ext_status(u_char stat_word[])
  777. {
  778.         u_char  buf[H8_MAX_CMD_SIZE];
  779. unsigned long flags;
  780.         memset(buf, 0, H8_MAX_CMD_SIZE); 
  781.         buf[0] = H8_RD_EXT_STATUS;
  782.         h8_q_cmd(buf, 1, 2);
  783. save_flags(flags); cli();
  784.         while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
  785.                 sleep_on(&h8_sync_wait); 
  786.         restore_flags(flags);
  787.         h8_sync_channel &= ~H8_GET_EXT_STATUS;
  788.         stat_word[0] = xx.byte[0];
  789.         stat_word[1] = xx.byte[1];
  790.         xx.word = 0;
  791.         if(h8_debug & 0x8) 
  792.                 printk("H8: curr ext status %x,  %xn",
  793.        stat_word[0], stat_word[1]);
  794.         return 0;
  795. }
  796. /*
  797.  * Thread attached to task 0 manages thermal/physcial state of Alphabook. 
  798.  * When a condition is detected by the interrupt service routine, the
  799.  * isr does a wakeup() on h8_monitor_wait.  The mask value is then
  800.  * screened for the appropriate action.
  801.  */
  802. int
  803. h8_monitor_thread(void * unused)
  804. {
  805.         u_char curr_temp[2];
  806.         /*
  807.          * Need a logic based safety valve here. During boot when this thread is
  808.          * started and the thermal interrupt is not yet initialized this logic 
  809.          * checks the temperature and acts accordingly.  When this path is acted
  810.          * upon system boot is painfully slow, however, the priority associated 
  811.          * with overheating is high enough to warrant this action.
  812.          */
  813.         h8_get_curr_temp(curr_temp);
  814.         printk(KERN_INFO "H8: Initial CPU temp: %dn", curr_temp[0]);
  815.         if(curr_temp[0] >= h8_uthermal_threshold) {
  816.                 h8_set_event_mask(H8_MANAGE_UTHERM);
  817.                 h8_manage_therm();
  818.         } else {
  819.                 /*
  820.                  * Arm the upper thermal limit of the H8 so that any temp in
  821.                  * excess will trigger the thermal control mechanism.
  822.                  */
  823.                 h8_set_upper_therm_thold(h8_uthermal_threshold);
  824.         }
  825.         for(;;) {
  826. sleep_on(&h8_monitor_wait);
  827.                 if(h8_debug & 0x2)
  828.                         printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%xn",
  829.                                 h8_event_mask);
  830.                 if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
  831.                         h8_manage_therm();
  832.                 }
  833. #if 0
  834.                 if (h8_event_mask & H8_POWER_BUTTON) {
  835.                         h8_system_down();
  836.                 }
  837. /*
  838.  * If an external DC supply is removed or added make 
  839.  * appropriate CPU speed adjustments.
  840.  */
  841.                 if (h8_event_mask & H8_MANAGE_BATTERY) {
  842.                           h8_run_level_3_manage(H8_RUN); 
  843.                           h8_clear_event_mask(H8_MANAGE_BATTERY);
  844.                 }
  845. #endif
  846.         }
  847. }
  848. /* 
  849.  * Function implements the following policy. When the machine is booted
  850.  * the system is set to run at full clock speed. When the upper thermal
  851.  * threshold is reached as a result of full clock a damping factor is 
  852.  * applied to cool off the cpu.  The default value is one quarter clock
  853.  * (57 Mhz).  When as a result of this cooling a temperature lower by
  854.  * hmc_uthermal_window is reached, the machine is reset to a higher 
  855.  * speed, one half clock (115 Mhz).  One half clock is maintained until
  856.  * the upper thermal threshold is again reached restarting the cycle.
  857.  */
  858. int
  859. h8_manage_therm(void)
  860. {
  861.         u_char curr_temp[2];
  862.         if(h8_event_mask & H8_MANAGE_UTHERM) {
  863. /* Upper thermal interrupt received, need to cool down. */
  864. if(h8_debug & 0x10)
  865.                         printk(KERN_WARNING "H8: Thermal threshold %d F reachedn",
  866.        h8_uthermal_threshold);
  867. h8_set_cpu_speed(h8_udamp); 
  868.                 h8_clear_event_mask(H8_MANAGE_UTHERM);
  869.                 h8_set_event_mask(H8_MANAGE_LTHERM);
  870.                 /* Check again in 30 seconds for CPU temperature */
  871.                 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); 
  872.         } else if (h8_event_mask & H8_MANAGE_LTHERM) {
  873. /* See how cool the system has become as a result
  874.    of the reduction in speed. */
  875.                 h8_get_curr_temp(curr_temp);
  876.                 last_temp = curr_temp[0];
  877.                 if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
  878. {
  879. /* System cooling has progressed to a point
  880.    that the CPU may be sped up. */
  881.                         h8_set_upper_therm_thold(h8_uthermal_threshold);
  882.                         h8_set_cpu_speed(h8_ldamp); /* adjustable */ 
  883.                         if(h8_debug & 0x10)
  884.                             printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d n",
  885.    h8_ldamp);
  886.                         h8_clear_event_mask(H8_MANAGE_LTHERM);
  887.                 }
  888. else /* Not cool enough yet, check again in 30 seconds. */
  889.                         h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
  890.         } else {
  891.                 
  892.         }
  893. return 0;
  894. }
  895. /* 
  896.  * Function conditions the value of global_rpb_counter before
  897.  * calling the primitive which causes the actual speed change.
  898.  */
  899. void
  900. h8_set_cpu_speed(int speed_divisor)
  901. {
  902. #ifdef NOT_YET
  903. /*
  904.  * global_rpb_counter is consumed by alpha_delay() in determining just
  905.  * how much time to delay.  It is necessary that the number of microseconds
  906.  * in DELAY(n) be kept consistent over a variety of CPU clock speeds.
  907.  * To that end global_rpb_counter is here adjusted.
  908.  */ 
  909.         
  910.         switch (speed_divisor) {
  911.                 case 0:
  912.                         global_rpb_counter = rpb->rpb_counter * 2L;
  913.                         break;
  914.                 case 1:
  915.                         global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
  916.                         break;
  917.                 case 3:
  918.                         global_rpb_counter = rpb->rpb_counter / 2L;
  919.                         break;
  920.                 case 4:
  921.                         global_rpb_counter = rpb->rpb_counter / 4L;
  922.                         break;
  923.                 case 5:
  924.                         global_rpb_counter = rpb->rpb_counter / 8L;
  925.                         break;
  926.                 /* 
  927.                  * This case most commonly needed for cpu_speed_divisor 
  928.                  * of 2 which is the value assigned by the firmware. 
  929.                  */
  930.                 default:
  931.                         global_rpb_counter = rpb->rpb_counter;
  932.                 break;
  933.         }
  934. #endif /* NOT_YET */
  935.         if(h8_debug & 0x8)
  936.                 printk(KERN_DEBUG "H8: Setting CPU speed to %d MHzn",
  937.        speed_tab[speed_divisor]); 
  938.          /* Make the actual speed change */
  939.         lca_clock_fiddle(speed_divisor);
  940. }
  941. /*
  942.  * Gets value stored in rpb representing CPU clock speed and adjusts this
  943.  * value based on the current clock speed divisor.
  944.  */
  945. u_long
  946. h8_get_cpu_speed(void)
  947. {
  948.         u_long speed = 0;
  949.         u_long counter;
  950. #ifdef NOT_YET
  951.         counter = rpb->rpb_counter / 1000000L;
  952.         switch (alphabook_get_clock()) {
  953.                 case 0:
  954.                         speed = counter * 2L;
  955.                         break;
  956.                 case 1:
  957.                         speed = counter * 4L / 3L ;
  958.                         break;
  959.                 case 2:
  960.                         speed = counter;
  961.                         break;
  962.                 case 3:
  963.                         speed = counter / 2L;
  964.                         break;
  965.                 case 4:
  966.                         speed = counter / 4L;
  967.                         break;
  968.                 case 5:
  969.                         speed = counter / 8L;
  970.                         break;
  971.                 default:
  972.                 break;
  973.         }
  974.         if(h8_debug & 0x8)
  975.                 printk(KERN_DEBUG "H8: CPU speed current setting: %d MHzn", speed); 
  976. #endif  /* NOT_YET */
  977. return speed;
  978. }
  979. static void
  980. h8_activate_monitor(unsigned long unused)
  981. {
  982. unsigned long flags;
  983. save_flags(flags); cli();
  984. h8_monitor_timer_active = 0;
  985. restore_flags(flags);
  986. wake_up(&h8_monitor_wait);
  987. }
  988. static void
  989. h8_start_monitor_timer(unsigned long secs)
  990. {
  991. unsigned long flags;
  992. if (h8_monitor_timer_active)
  993.     return;
  994. save_flags(flags); cli();
  995. h8_monitor_timer_active = 1;
  996. restore_flags(flags);
  997.         init_timer(&h8_monitor_timer);
  998.         h8_monitor_timer.function = h8_activate_monitor;
  999.         h8_monitor_timer.expires = secs * HZ + jiffies;
  1000.         add_timer(&h8_monitor_timer);
  1001. }
  1002. static void h8_set_event_mask(int mask)
  1003. {
  1004. unsigned long flags;
  1005. save_flags(flags); cli();
  1006. h8_event_mask |= mask;
  1007. restore_flags(flags);
  1008. }
  1009. static void h8_clear_event_mask(int mask)
  1010. {
  1011. unsigned long flags;
  1012. save_flags(flags); cli();
  1013. h8_event_mask &= (~mask);
  1014. restore_flags(flags);
  1015. }
  1016. MODULE_LICENSE("GPL");
  1017. EXPORT_NO_SYMBOLS;