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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* apc - Driver implementation for power management functions
  2.  * of Aurora Personality Chip (APC) on SPARCstation-4/5 and
  3.  * derivatives.
  4.  *
  5.  * Copyright (c) 2002 Eric Brower (ebrower@usa.net)
  6.  */
  7. #include <linux/kernel.h>
  8. #include <linux/fs.h>
  9. #include <linux/errno.h>
  10. #include <linux/init.h>
  11. #include <linux/miscdevice.h>
  12. #include <linux/pm.h>
  13. #include <asm/io.h>
  14. #include <asm/sbus.h>
  15. #include <asm/oplib.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/auxio.h>
  18. #include <asm/apc.h>
  19. /* Debugging
  20.  * 
  21.  * #define APC_DEBUG_LED
  22.  * #define APC_NO_IDLE
  23.  */
  24. #define APC_MINOR MISC_DYNAMIC_MINOR
  25. #define APC_OBPNAME "power-management"
  26. #define APC_DEVNAME "apc"
  27. volatile static u8 *regs; 
  28. static int apc_regsize;
  29. #define apc_readb(offs) (sbus_readb(regs+offs))
  30. #define apc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
  31. /* 
  32.  * CPU idle callback function
  33.  * See .../arch/sparc/kernel/process.c
  34.  */
  35. void apc_swift_idle(void)
  36. {
  37. #ifdef APC_DEBUG_LED
  38. set_auxio(0x00, AUXIO_LED); 
  39. #endif
  40. apc_writeb(apc_readb(APC_IDLE_REG) | APC_IDLE_ON, APC_IDLE_REG);
  41. #ifdef APC_DEBUG_LED
  42. set_auxio(AUXIO_LED, 0x00); 
  43. #endif
  44. static inline void apc_free(void)
  45. {
  46. sbus_iounmap((unsigned long)regs, apc_regsize);
  47. }
  48. static int apc_open(struct inode *inode, struct file *f)
  49. {
  50. return 0;
  51. }
  52. static int apc_release(struct inode *inode, struct file *f)
  53. {
  54. return 0;
  55. }
  56. static int apc_ioctl(struct inode *inode, struct file *f, 
  57.      unsigned int cmd, unsigned long arg)
  58. {
  59. __u8 inarg;
  60. switch (cmd) {
  61. case APCIOCGFANCTL:
  62. if(put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, (__u8*) arg)) {
  63. return -EFAULT;
  64. }
  65. break;
  66. case APCIOCGCPWR:
  67. if(put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, (__u8*) arg)) {
  68. return -EFAULT;
  69. }
  70. break;
  71. case APCIOCGBPORT:
  72. if(put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, (__u8*) arg)) {
  73. return -EFAULT;
  74. }
  75. break;
  76. case APCIOCSFANCTL:
  77. if(get_user(inarg, (__u8*) arg)) {
  78. return -EFAULT;
  79. }
  80. apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
  81. break;
  82. case APCIOCSCPWR:
  83. if(get_user(inarg, (__u8*) arg)) {
  84. return -EFAULT;
  85. }
  86. apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
  87. break;
  88. case APCIOCSBPORT:
  89. if(get_user(inarg, (__u8*) arg)) {
  90. return -EFAULT;
  91. }
  92. apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
  93. break;
  94. default:
  95. return -EINVAL;
  96. };
  97. return 0;
  98. }
  99. static struct file_operations apc_fops = {
  100. ioctl: apc_ioctl,
  101. open: apc_open,
  102. release: apc_release,
  103. };
  104. static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
  105. static int __init apc_probe(void)
  106. {
  107. struct sbus_bus *sbus = NULL;
  108. struct sbus_dev *sdev = NULL;
  109. int iTmp = 0;
  110. for_each_sbus(sbus) {
  111. for_each_sbusdev(sdev, sbus) {
  112. if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
  113. goto sbus_done;
  114. }
  115. }
  116. }
  117. sbus_done:
  118. if (!sdev) {
  119. return -ENODEV;
  120. }
  121. apc_regsize = sdev->reg_addrs[0].reg_size;
  122. regs = (u8*) sbus_ioremap(&sdev->resource[0], 0, 
  123.    apc_regsize, APC_OBPNAME);
  124. if(NULL == regs) {
  125. printk(KERN_ERR "%s: unable to map registersn", APC_DEVNAME);
  126. return -ENODEV;
  127. }
  128. iTmp = misc_register(&apc_miscdev);
  129. if (iTmp != 0) {
  130. printk(KERN_ERR "%s: unable to register devicen", APC_DEVNAME);
  131. apc_free();
  132. return -ENODEV;
  133. }
  134. #ifndef APC_NO_IDLE
  135. /* Assign power management IDLE handler */
  136. pm_idle = apc_swift_idle;
  137. #endif
  138. printk(KERN_INFO "%s: power management initializedn", APC_DEVNAME);
  139. return 0;
  140. }
  141. /* This driver is not critical to the boot process
  142.  * and is easiest to ioremap when SBus is already
  143.  * initialized, so we install ourselves thusly:
  144.  */
  145. __initcall(apc_probe);