apm2.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * bios-less APM driver for ARM Linux 
  3.  *  Jamey Hicks <jamey@crl.dec.com>
  4.  *  adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
  5.  *
  6.  * APM 1.2 Reference:
  7.  *   Intel Corporation, Microsoft Corporation. Advanced Power Management
  8.  *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
  9.  *
  10.  * [This document is available from Microsoft at:
  11.  *    http://www.microsoft.com/hwdev/busbios/amp_12.htm]
  12.  *
  13.    Thr 29 Nov 2001 Nandy Lyu <nandy@mizi.com>
  14.    - Modified for MIZI Power Management
  15.    Mon 14 Jan 2002 Yong-iL Joh <tolkien@mizi.com>
  16.    - modified followed by MIZI's "kernel vs Application API spec (0.3, draft)"
  17.    Fri May 10 2002 Yong-iL Joh <tolkien@mizi.com>
  18.    - kernel vs app. API spec (draft) v1.33
  19.  *
  20.  * This file is subject to the terms and conditions of the GNU General Public
  21.  * License.  See the file COPYING in the main directory of this archive
  22.  * for more details.
  23.  */
  24. #include <linux/config.h>
  25. #include <linux/module.h>
  26. #include <linux/kernel.h>
  27. #include <linux/init.h>
  28. #include <linux/poll.h>
  29. #include <linux/miscdevice.h>
  30. #include <linux/apm_bios.h>
  31. #include <linux/pm.h>
  32. #include <linux/errno.h>
  33. #include <asm/hardware.h>
  34. #include <linux/proc_fs.h>
  35. /*
  36.  *  Debug macros 
  37.  */
  38. /* 0 : Quiet 1 : Audible 2 : Loud 3 : Noisy */
  39. #undef CONFIG_APM_DEBUG 1
  40. #ifdef CONFIG_APM_DEBUG
  41. #define DEBUG(n, args...)
  42. if (n <= CONFIG_APM_DEBUG) {
  43.     printk(KERN_INFO args);
  44. }
  45. #else
  46. #define DEBUG(n, args...)
  47. #endif
  48. extern wait_queue_head_t mz_event_queue;
  49. #define INCBUF(x,mod) (((x)+1) & ((mod) - 1))
  50. extern struct mz_event_queue_t mz_event_q;
  51. extern int pm_suggest_suspend(void);
  52. extern int pm_do_suspend(void);
  53. static int apm_bios_ioctl(struct inode * inode, struct file *filp,
  54.     u_int cmd, u_long arg)
  55. {
  56.     int ret = 0;
  57.     struct pm_dev *pm_dev = NULL;
  58.     static int apm_lcd_status = LCD_ON;
  59.     switch (cmd) {
  60.     case APM_IOC_SUSPEND:
  61. //      pm_suggest_suspend();
  62.       break;
  63.     case APM_MZ_SLEEP:
  64.       pm_do_suspend();
  65.       break;
  66.     case APM_LCD_OFF:
  67.       DEBUG(2, __FILE__ ": LCD OFFn");
  68.       while ((pm_dev = pm_find(PM_USER_DEV, pm_dev)) != NULL) {
  69. if ((pm_dev->id == PM_USER_LCD) || (pm_dev->id == PM_USER_LIGHT)) {
  70.   DEBUG(2, __FILE__ ": find LCD devicen");
  71.   ret = pm_send(pm_dev, PM_SUSPEND, (void *)2);
  72.   if (ret) {
  73.     DEBUG(1, __FILE__ ": error in pm_send(0x%lx)n", pm_dev->id);
  74.     return ret;
  75.   }
  76. }
  77.       }
  78.       apm_lcd_status = LCD_OFF;
  79.       break;
  80.     case APM_LCD_ON:
  81.       DEBUG(2, __FILE__ ": LCD ONn");
  82.       while ((pm_dev = pm_find(PM_USER_DEV, pm_dev)) != NULL) {
  83. if ((pm_dev->id == PM_USER_LCD) || (pm_dev->id == PM_USER_LIGHT)) {
  84.   DEBUG(2, __FILE__ ": find LCD devicen");
  85.   ret = pm_send(pm_dev, PM_RESUME, (void *)0);
  86.   if (ret) {
  87.     DEBUG(1, __FILE__ ": error in pm_send(0x%lx)n", pm_dev->id);
  88.     return ret;
  89.   }
  90. }
  91.       }
  92.       apm_lcd_status = LCD_ON;
  93.       break;
  94.     case APM_DEV_LIST:
  95. #ifdef CONFIG_APM_DEBUG
  96.       printk("type tt id tt state t prev_state n");
  97.       while ((pm_dev = pm_find(PM_UNKNOWN_DEV, pm_dev)) != NULL) {
  98. printk("0x%08x t 0x%08lx t %d t %dn",
  99.        (int)pm_dev->type, (unsigned long)pm_dev->id,
  100.        (int)pm_dev->state, (int)pm_dev->prev_state);
  101.       }
  102. #endif
  103.       break;
  104.     case APM_DEV_ONOFF: {
  105.       struct pm_dev *pm_dev2;
  106.       pm_dev2 = (struct pm_dev *)kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
  107.       if (pm_dev2 == NULL)
  108. return -ENOMEM;
  109.       ret = copy_from_user(pm_dev2, (struct pm_dev *)arg,
  110.    sizeof(struct pm_dev));
  111.       if (ret)
  112. return ret;
  113.       while ((pm_dev = pm_find(pm_dev2->type, pm_dev)) != NULL) {
  114. if (pm_dev->id == pm_dev2->id)
  115.   ret = pm_send(pm_dev, pm_dev2->state, pm_dev2->data);
  116. break;
  117.       }
  118.       kfree(pm_dev2);
  119.       return ret;
  120.     } break;
  121.     case GET_BATTERY_STATUS: {
  122.       BATTERY_RET bat_dev = {
  123. sec: 0,
  124. level: -1,
  125. ac: AC_UNKNOWN,
  126. battery: BATTERY_UNKNOWN,
  127.       };
  128.       if (mz_pm_ops.get_power_status == NULL)
  129. return -EIO;
  130.       if (!(ret = (*(mz_pm_ops.get_power_status))(&bat_dev))) {
  131. if (copy_to_user((BATTERY_RET *)arg, &bat_dev, sizeof(BATTERY_RET)))
  132.     return -EINVAL;
  133.       } else return -EIO;
  134.     } break;
  135.     case GET_JIFFIES:
  136.       return put_user(pm_last_jiffies, (unsigned long *)arg);
  137.       break;
  138.     case GET_LCD_STATUS:
  139.       return put_user(apm_lcd_status, (unsigned int *)arg);
  140.       break;
  141.     case GET_MZ_EVENT:
  142.       if (mz_event_q.head == mz_event_q.tail)
  143. return -EAGAIN;
  144.       else {
  145. ret = put_user(mz_event_q.buf[mz_event_q.tail], (unsigned long *)arg);
  146. mz_event_q.tail = INCBUF(mz_event_q.tail, MZ_EVENT_BUF_SIZE);
  147. return ret;
  148.       }
  149.       break;
  150.     case SET_INPUT_DEV: {
  151.       unsigned int apm_input_tmp;
  152.       ret = get_user(apm_input_tmp, (unsigned int *)arg);
  153.       if (ret)
  154. return ret;
  155.       while ((pm_dev = pm_find(PM_USER_DEV, pm_dev)) != NULL) {
  156. if (pm_dev->id == PM_USER_INPUT) {
  157.   if (apm_input_tmp == INPUT_DEV_ON)
  158.     ret = pm_send(pm_dev, PM_RESUME, NULL);
  159.   else if (apm_input_tmp == INPUT_DEV_OFF)
  160.     ret = pm_send(pm_dev, PM_SUSPEND, NULL);
  161.   else
  162.     return -EINVAL;
  163. }
  164.       }
  165.       return ret;
  166.     } break;
  167.     default:
  168.       return -ENOIOCTLCMD;
  169.     }
  170.     return 0;
  171. }
  172. static unsigned int apm_bios_poll(struct file *filp, poll_table *wait)
  173. {
  174.     poll_wait(filp, &mz_event_queue, wait);
  175.     return (mz_event_q.head == mz_event_q.tail ? 0 : (POLLIN | POLLRDNORM));
  176. }
  177. struct file_operations apm_bios_fops = {
  178.     owner: THIS_MODULE,
  179.     ioctl: apm_bios_ioctl,
  180.     poll: apm_bios_poll,
  181. };
  182. static struct miscdevice apm_device = {
  183. MISC_DYNAMIC_MINOR,
  184. "apm_bios",
  185. &apm_bios_fops
  186. };
  187. /*
  188.  * Just start the APM thread. We do NOT want to do APM BIOS
  189.  * calls from anything but the APM thread, if for no other reason
  190.  * than the fact that we don't trust the APM BIOS. This way,
  191.  * most common APM BIOS problems that lead to protection errors
  192.  * etc will have at least some level of being contained...
  193.  *
  194.  * In short, if something bad happens, at least we have a choice
  195.  * of just killing the apm thread..
  196.  */
  197. static int __init apm_init(void)
  198. {
  199.     if (PM_IS_ACTIVE()) {
  200.       printk(KERN_NOTICE "apm: overridden by ACPI.n");
  201.       return -1;
  202.     }
  203.     pm_active = 1;
  204.     misc_register(&apm_device);
  205.     return 0;
  206. }
  207. static void __exit apm_exit(void)
  208. {
  209.     misc_deregister(&apm_device);
  210.     pm_active = 0;
  211. }
  212. module_init(apm_init);
  213. module_exit(apm_exit);
  214. MODULE_AUTHOR("Yong-iL Joh");
  215. MODULE_DESCRIPTION("Advanced Power Management by MIZI");
  216. EXPORT_NO_SYMBOLS;