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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: display7seg.c,v 1.5 2001/10/08 22:19:51 davem Exp $
  2.  *
  3.  * display7seg - Driver implementation for the 7-segment display
  4.  * present on Sun Microsystems CP1400 and CP1500
  5.  *
  6.  * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
  7.  *
  8.  */
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/version.h>
  12. #include <linux/fs.h>
  13. #include <linux/errno.h>
  14. #include <linux/major.h>
  15. #include <linux/init.h>
  16. #include <linux/miscdevice.h>
  17. #include <linux/ioport.h> /* request_region, check_region */
  18. #include <asm/ebus.h> /* EBus device */
  19. #include <asm/oplib.h> /* OpenProm Library  */
  20. #include <asm/uaccess.h> /* put_/get_user */
  21. #include <asm/display7seg.h>
  22. #define D7S_MINOR 193
  23. #define D7S_OBPNAME "display7seg"
  24. #define D7S_DEVNAME "d7s"
  25. static int sol_compat = 0; /* Solaris compatibility mode */
  26. #ifdef MODULE
  27. EXPORT_NO_SYMBOLS;
  28. /* Solaris compatibility flag -
  29.  * The Solaris implementation omits support for several
  30.  * documented driver features (ref Sun doc 806-0180-03).  
  31.  * By default, this module supports the documented driver 
  32.  * abilities, rather than the Solaris implementation:
  33.  *
  34.  *  1) Device ALWAYS reverts to OBP-specified FLIPPED mode
  35.  *     upon closure of device or module unload.
  36.  *  2) Device ioctls D7SIOCRD/D7SIOCWR honor toggling of
  37.  *     FLIP bit
  38.  *
  39.  * If you wish the device to operate as under Solaris,
  40.  * omitting above features, set this parameter to non-zero.
  41.  */
  42. MODULE_PARM
  43. (sol_compat, "1i");
  44. MODULE_PARM_DESC
  45. (sol_compat, 
  46.  "Disables documented functionality omitted from Solaris driver");
  47. MODULE_AUTHOR
  48. ("Eric Brower <ebrower@usa.net>");
  49. MODULE_DESCRIPTION
  50. ("7-Segment Display driver for Sun Microsystems CP1400/1500");
  51. MODULE_LICENSE("GPL");
  52. MODULE_SUPPORTED_DEVICE
  53. ("d7s");
  54. #endif /* ifdef MODULE */
  55. /*
  56.  * Register block address- see header for details
  57.  * -----------------------------------------
  58.  * | DP | ALARM | FLIP | 4 | 3 | 2 | 1 | 0 |
  59.  * -----------------------------------------
  60.  *
  61.  * DP  - Toggles decimal point on/off 
  62.  * ALARM - Toggles "Alarm" LED green/red
  63.  * FLIP - Inverts display for upside-down mounted board
  64.  * bits 0-4 - 7-segment display contents
  65.  */
  66. volatile u8* d7s_regs = 0;
  67. static inline void d7s_free(void)
  68. {
  69. iounmap(d7s_regs);
  70. }
  71. static inline int d7s_obpflipped(void)
  72. {
  73. int opt_node;
  74. opt_node = prom_getchild(prom_root_node);
  75. opt_node = prom_searchsiblings(opt_node, "options");
  76. return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1);
  77. }
  78. static int d7s_open(struct inode *inode, struct file *f)
  79. {
  80. if (D7S_MINOR != MINOR(inode->i_rdev))
  81. return -ENODEV;
  82. MOD_INC_USE_COUNT;
  83. return 0;
  84. }
  85. static int d7s_release(struct inode *inode, struct file *f)
  86. {
  87. if (D7S_MINOR != MINOR(inode->i_rdev))
  88. return -ENODEV;
  89. MOD_DEC_USE_COUNT;
  90. /* Reset flipped state to OBP default only if
  91.  * no other users have the device open and we
  92.  * are not operating in solaris-compat mode
  93.  */
  94. if (0 == MOD_IN_USE && 0 == sol_compat) {
  95. int regval = 0;
  96. regval = readb(d7s_regs);
  97. (0 == d7s_obpflipped()) ? 
  98. writeb(regval |= D7S_FLIP,  d7s_regs): 
  99. writeb(regval &= ~D7S_FLIP, d7s_regs);
  100. }
  101. return 0;
  102. }
  103. static int d7s_ioctl(struct inode *inode, struct file *f, 
  104.      unsigned int cmd, unsigned long arg)
  105. {
  106. __u8 regs = readb(d7s_regs);
  107. __u8 ireg = 0;
  108. if (D7S_MINOR != MINOR(inode->i_rdev))
  109. return -ENODEV;
  110. switch (cmd) {
  111. case D7SIOCWR:
  112. /* assign device register values
  113.  * we mask-out D7S_FLIP if in sol_compat mode
  114.  */
  115. if (get_user(ireg, (int *) arg))
  116. return -EFAULT;
  117. if (0 != sol_compat) {
  118. (regs & D7S_FLIP) ? 
  119. (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
  120. }
  121. writeb(ireg, d7s_regs);
  122. break;
  123. case D7SIOCRD:
  124. /* retrieve device register values
  125.  * NOTE: Solaris implementation returns D7S_FLIP bit
  126.  * as toggled by user, even though it does not honor it.
  127.  * This driver will not misinform you about the state
  128.  * of your hardware while in sol_compat mode
  129.  */
  130. if (put_user(regs, (int *) arg))
  131. return -EFAULT;
  132. break;
  133. case D7SIOCTM:
  134. /* toggle device mode-- flip display orientation */
  135. (regs & D7S_FLIP) ? 
  136. (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
  137. writeb(regs, d7s_regs);
  138. break;
  139. };
  140. return 0;
  141. }
  142. static struct file_operations d7s_fops = {
  143. owner: THIS_MODULE,
  144. ioctl: d7s_ioctl,
  145. open: d7s_open,
  146. release: d7s_release,
  147. };
  148. static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
  149. static int __init d7s_init(void)
  150. {
  151. struct linux_ebus *ebus = NULL;
  152. struct linux_ebus_device *edev = NULL;
  153. int iTmp = 0, regs = 0;
  154. for_each_ebus(ebus) {
  155. for_each_ebusdev(edev, ebus) {
  156. if (!strcmp(edev->prom_name, D7S_OBPNAME))
  157. goto ebus_done;
  158. }
  159. }
  160. ebus_done:
  161. if(!edev) {
  162. printk("%s: unable to locate devicen", D7S_DEVNAME);
  163. return -ENODEV;
  164. }
  165. d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
  166. iTmp = misc_register(&d7s_miscdev);
  167. if (0 != iTmp) {
  168. printk("%s: unable to acquire miscdevice minor %in",
  169.        D7S_DEVNAME, D7S_MINOR);
  170. return iTmp;
  171. }
  172. /* OBP option "d7s-flipped?" is honored as default
  173.  * for the device, and reset default when detached
  174.  */
  175. regs = readb(d7s_regs);
  176. iTmp = d7s_obpflipped();
  177. (0 == iTmp) ? 
  178. writeb(regs |= D7S_FLIP,  d7s_regs): 
  179. writeb(regs &= ~D7S_FLIP, d7s_regs);
  180. printk("%s: 7-Segment Display%s at 0x%lx %sn", 
  181.        D7S_DEVNAME,
  182.        (0 == iTmp) ? (" (FLIPPED)") : (""),
  183.        edev->resource[0].start,
  184.        (0 != sol_compat) ? ("in sol_compat mode") : (""));
  185. return 0;
  186. }
  187. static void __exit d7s_cleanup(void)
  188. {
  189. int regs = readb(d7s_regs);
  190. /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
  191. if (0 == sol_compat) {
  192. (0 == d7s_obpflipped()) ? 
  193. writeb(regs |= D7S_FLIP,  d7s_regs):
  194. writeb(regs &= ~D7S_FLIP, d7s_regs);
  195. }
  196. misc_deregister(&d7s_miscdev);
  197. d7s_free();
  198. }
  199. module_init(d7s_init);
  200. module_exit(d7s_cleanup);