MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / char / moxa_misc.c
blob46d356ae3450a6723f28a121b4c29fa1b4792a92
1 /*
2 * This is Moxa CPU device driver.
3 * This device driver will control the READY LED & RESET button.
4 * Also this device driver will control debug LED.
5 * It is from misc interface. So the device node major number is 10.
6 * The device node minor number is following:
7 * mxmisc: 105
9 * History:
10 * Date Aurhor Comment
11 * 02-22-2006 Victor Yu. Create it.
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/types.h>
17 #include <linux/miscdevice.h>
18 #include <linux/fcntl.h>
19 #include <linux/init.h>
20 #include <linux/poll.h>
21 #include <linux/proc_fs.h>
22 #include <linux/spinlock.h>
23 #include <linux/delay.h>
24 #include <linux/rtc.h>
25 #include <linux/timer.h>
26 #include <linux/ioport.h>
27 #include <linux/kmod.h>
29 #include <asm/io.h>
30 #include <asm/uaccess.h>
31 #include <asm/system.h>
32 #include <asm/arch/cpe/cpe.h>
33 #include <asm/arch/gpio.h>
35 #define MOXA_MISC_MINOR 105
37 #if (defined CONFIG_ARCH_IA241_32128)||(defined CONFIG_ARCH_IA241_16128)// add by Victor Yu. 05-22-2007
38 #define CONFIG_ARCH_IA241
39 #endif
41 #if (defined CONFIG_ARCH_UC_7112_LX_PLUS_LITON)
42 #define CONFIG_ARCH_UC_7112_LX_PLUS
43 #endif
45 #if defined(CONFIG_ARCH_IA240) || defined(CONFIG_ARCH_IA241) || defined(CONFIG_ARCH_W341) || defined(CONFIG_ARCH_W345) || defined(CONFIG_ARCH_W345_IMP1) || defined(CONFIG_ARCH_UC_7112_LX_PLUS) || defined(CONFIG_ARCH_W321)|| defined(CONFIG_ARCH_W311) || defined(CONFIG_ARCH_W325) || defined(CONFIG_ARCH_W315)
46 #define SW_READY_GPIO (1<<27)
47 #define SW_RESET_GPIO (1<<25)
48 #else
49 #define SW_READY_GPIO (1<<4)
50 #define SW_RESET_GPIO (1<<23)
51 #endif
53 #if defined(CONFIG_ARCH_IA240) || defined(CONFIG_ARCH_IA241) // mask by Victor Yu. 04-20-2007
54 #define DEBUG_LED_0 (1<<0)
55 #define DEBUG_LED_1 (1<<1)
56 #define DEBUG_LED_2 (1<<2)
57 #define DEBUG_LED_3 (1<<3)
58 #define DEBUG_LED (DEBUG_LED_0|DEBUG_LED_1|DEBUG_LED_2|DEBUG_LED_3)
59 #endif
61 #define RESET_POLL_TIME (HZ/5)
62 #define RESET_TIMEOUT (HZ * 5)
65 // file operaiton function call
67 #define IOCTL_SW_READY_ON 1
68 #define IOCTL_SW_READY_OFF 2
70 #if defined(CONFIG_ARCH_IA240) || defined(CONFIG_ARCH_IA241)//0 // mask by Victor Yu. 04-20---2007
71 #define IOCTL_DEBUG_LED_OUT 0x100
72 #endif
74 static struct timer_list resettimer;
75 static spinlock_t resetlock=SPIN_LOCK_UNLOCKED;
76 static unsigned long endresettime, intervaltime;
77 static int ledonoffflag;
78 static struct work_struct resetqueue;
80 static void settodefault(void *unused)
82 char *argv[2], *envp[5];
84 if ( in_interrupt() )
85 return;
86 if ( !current->fs->root )
87 return;
88 argv[0] = "/bin/setdef";
89 argv[1] = 0;
90 envp[0] = "HOME=/";
91 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
92 envp[2] = 0;
93 call_usermodehelper(argv[0], argv, envp, 0);
96 static void reset_poll(unsigned long ingore)
98 spin_lock(&resetlock);
99 del_timer(&resettimer);
100 if ( !mcpu_gpio_get(SW_RESET_GPIO) ) {
101 if ( endresettime == 0 ) {
102 endresettime = jiffies + RESET_TIMEOUT;
103 intervaltime = jiffies + HZ;
104 } else if ( time_after(jiffies, endresettime) ){
105 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_HIGH);
106 schedule_work(&resetqueue);
107 goto poll_exit;
108 } else if ( time_after(jiffies, intervaltime) ) {
109 if ( ledonoffflag ) {
110 ledonoffflag = 0;
111 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_HIGH);
112 } else {
113 ledonoffflag = 1;
114 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_LOW);
116 intervaltime = jiffies + HZ;
118 } else if ( endresettime ) {
119 endresettime = 0;
120 ledonoffflag = 1;
121 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_LOW);
123 resettimer.function = reset_poll;
124 resettimer.expires = jiffies + RESET_POLL_TIME;
125 add_timer(&resettimer);
126 poll_exit:
127 spin_unlock(&resetlock);
130 static int mxmisc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
132 switch ( cmd ) {
133 case IOCTL_SW_READY_ON :
134 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_LOW);
135 break;
136 case IOCTL_SW_READY_OFF :
137 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_HIGH);
138 break;
139 #if defined(CONFIG_ARCH_IA240) || defined(CONFIG_ARCH_IA241)//0 // mask by Victor Yu. 04-20-2007
140 case IOCTL_DEBUG_LED_OUT :
142 unsigned int val;
143 if ( copy_from_user(&val, (unsigned int *)arg, sizeof(unsigned int)) )
144 return -EFAULT;
145 if ( val & 1 )
146 mcpu_gpio_set(DEBUG_LED_0, MCPU_GPIO_LOW);
147 else
148 mcpu_gpio_set(DEBUG_LED_0, MCPU_GPIO_HIGH);
149 if ( val & 2 )
150 mcpu_gpio_set(DEBUG_LED_1, MCPU_GPIO_LOW);
151 else
152 mcpu_gpio_set(DEBUG_LED_1, MCPU_GPIO_HIGH);
153 if ( val & 4 )
154 mcpu_gpio_set(DEBUG_LED_2, MCPU_GPIO_LOW);
155 else
156 mcpu_gpio_set(DEBUG_LED_2, MCPU_GPIO_HIGH);
157 if ( val & 8 )
158 mcpu_gpio_set(DEBUG_LED_3, MCPU_GPIO_LOW);
159 else
160 mcpu_gpio_set(DEBUG_LED_3, MCPU_GPIO_HIGH);
161 break;
163 #endif
164 default:
165 return -EINVAL;
167 return 0;
170 static int mxmisc_open(struct inode *inode, struct file *file)
172 if ( MINOR(inode->i_rdev) == MOXA_MISC_MINOR )
173 return 0;
174 return -ENODEV;
177 static int mxmisc_release(struct inode *inode, struct file *file)
179 return 0;
182 static struct file_operations mxmisc_fops = {
183 owner:THIS_MODULE,
184 llseek:NULL,
185 ioctl:mxmisc_ioctl,
186 open:mxmisc_open,
187 release:mxmisc_release,
189 static struct miscdevice mxmisc_dev = {
190 MOXA_MISC_MINOR,
191 "mxmisc",
192 &mxmisc_fops
195 static void __exit mxmisc_exit(void)
197 spin_lock(&resetlock);
198 del_timer(&resettimer);
199 spin_unlock(&resetlock);
200 misc_deregister(&mxmisc_dev);
203 static int __init mxmisc_init(void)
205 printk("Register Moxa misc ver1.0 ");
206 if ( misc_register(&mxmisc_dev) ) {
207 printk("fail !\n");
208 return -ENOMEM;
211 // set the CPU for GPIO
212 mcpu_gpio_mp_set(SW_READY_GPIO|SW_RESET_GPIO);
213 // default set all GPIO for input/ouput
214 mcpu_gpio_inout(SW_READY_GPIO, MCPU_GPIO_OUTPUT);
215 mcpu_gpio_inout(SW_RESET_GPIO, MCPU_GPIO_INPUT);
216 mcpu_gpio_set(SW_READY_GPIO, MCPU_GPIO_HIGH);
218 #if defined(CONFIG_ARCH_IA240) || defined(CONFIG_ARCH_IA241)//0 // mask by Victor Yu. 04-20-2007
219 // set the debug led output
220 mcpu_gpio_inout(DEBUG_LED, MCPU_GPIO_OUTPUT);
221 #endif
223 // initialize the reset polling
224 INIT_WORK(&resetqueue, settodefault, NULL);
225 spin_lock(&resetlock);
226 endresettime = 0;
227 ledonoffflag = 1;
228 init_timer(&resettimer);
229 resettimer.function = reset_poll;
230 resettimer.expires = jiffies + RESET_POLL_TIME;
231 add_timer(&resettimer);
232 spin_unlock(&resetlock);
234 printk("OK.\n");
235 return 0;
238 module_init(mxmisc_init);
239 module_exit(mxmisc_exit);
241 MODULE_AUTHOR("Victor Yu");
242 MODULE_LICENSE("GPL");