MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / char / moxa_w325_dio.c
blobd65c77d284a48c962eb08a9d81f798d24c3bed39
1 /*
2 * This is Moxa IA261 DI/DO device driver.
3 * It is from misc interface. So the device node major number is 8.
4 * The device node minor number is following:
5 * dio: 104
7 * History:
8 * Date Aurhor Comment
9 * 12-13-2007 Victor Yu. Create it.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/miscdevice.h>
15 #include <linux/fcntl.h>
16 #include <linux/init.h>
17 #include <linux/poll.h>
18 #include <linux/proc_fs.h>
19 #include <linux/spinlock.h>
20 #include <linux/delay.h>
21 #include <linux/rtc.h>
22 #include <linux/timer.h>
23 #include <linux/ioport.h>
24 #include <linux/proc_fs.h>
26 #include <asm/io.h>
27 #include <asm/uaccess.h>
28 #include <asm/system.h>
29 #include <asm/arch/cpe/cpe.h>
31 #define MOXA_DIO_MINOR 107
33 #define DI_PADDR 0x88000000
34 #define DO_PADDR 0x84000000
36 static unsigned int di_addr;
37 static unsigned int do_addr;
38 static unsigned char do_state_keep=0;
41 // DIO file operaiton function call
43 #define MAX_DIO 4
45 #define DIO_INPUT 1
46 #define DIO_OUTPUT 0
47 #define DIO_HIGH 1
48 #define DIO_LOW 0
49 #define IOCTL_DIO_GET_MODE 1
50 #define IOCTL_DIO_SET_MODE 2
51 #define IOCTL_DIO_GET_DATA 3
52 #define IOCTL_DIO_SET_DATA 4
53 #define IOCTL_SET_DOUT 15
54 #define IOCTL_GET_DOUT 16
55 #define IOCTL_GET_DIN 17
56 struct dio_set_struct {
57 int io_number;
58 int mode_data; // 1 for input, 0 for output, 1 for high, 0 for low
62 struct proc_dir_entry* dio_proc;
63 #define dio_proc_name "driver/dio1"
64 int dio_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
66 char *out = page;
67 int pin_count, len;
68 unsigned char di_state;
70 for ( pin_count = 0; pin_count < MAX_DIO; pin_count++ )
71 out += sprintf(out, "DO[%d]:%s\n", pin_count, do_state_keep&(1<<pin_count)?"HIGH":"LOW");
72 di_state = inb(di_addr);
73 for ( pin_count = 0; pin_count < MAX_DIO; pin_count++ )
74 out += sprintf(out, "DI[%d]:%s\n", pin_count, di_state&(1<<pin_count)?"HIGH":"LOW");
76 len = out -page - off;
77 if (len < count) {
78 *eof = 1;
79 if (len <= 0)
80 return 0;
81 } else
82 len = count;
83 *start = page + off;
85 return len;
88 int dio_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
90 char kbuffer[64], mode[2], pin[3];
91 int num_count, var_num, byte_count;
93 if ( copy_from_user(kbuffer, (char*)buffer , count) )
94 return -EFAULT;
96 kbuffer[count+1] = '\0';
97 memset(pin,0,3);
98 memset(mode,0,2);
99 num_count = var_num = 0 ;
101 for ( byte_count = 0 ; byte_count < count ; byte_count++ ) {
102 if ( kbuffer[byte_count] != ' ' && kbuffer[byte_count] != '\0' && kbuffer[byte_count] != '\n' ) {
103 if ( var_num == 0 ) {
104 num_count++;
105 if ( num_count > 2 ) {
106 printk("The max pin number is %d !!\n",MAX_DIO);
107 return -EINVAL;
109 pin[num_count-1] = kbuffer[byte_count];
110 pin[num_count] = '\0';
112 if ( var_num == 1 ) { // to read high or low for output(DO) mode
113 num_count++;
114 if ( num_count > 1 ) {
115 printk("The high = %d, low = %d !!\n", DIO_HIGH, DIO_LOW);
116 return -EINVAL;
118 mode[num_count-1] = kbuffer[byte_count];
119 mode[num_count] = '\0';
121 } else {
122 if ( pin[0] != 0 ) {
123 var_num = 1;
124 num_count = 0;
129 num_count = simple_strtol(pin, NULL, 0); // to keep pin number
130 byte_count = simple_strtol(mode, NULL, 0); // to keep state setting
132 if ( num_count >= MAX_DIO ) {
133 //printk("The max pin number is %d !!\n",MAX_GPIO-1);
134 goto error_write_proc;
137 if ( byte_count == DIO_HIGH )
138 do_state_keep |= (1 << num_count);
139 else if ( byte_count == DIO_LOW )
140 do_state_keep &= ~(1<< num_count);
141 else
142 goto error_write_proc;
143 outb(do_state_keep, do_addr);
145 return count;
147 error_write_proc:
148 return -EINVAL;
151 static int dio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
153 struct dio_set_struct set;
154 unsigned char di_state;
156 switch ( cmd ) {
157 case IOCTL_SET_DOUT :
158 if ( copy_from_user(&set, (struct dio_set_struct *)arg, sizeof(struct dio_set_struct)) )
159 return -EFAULT;
160 if ( set.io_number < 0 || set.io_number >= MAX_DIO )
161 return -EINVAL;
162 if ( set.mode_data == DIO_HIGH )
163 do_state_keep |= (1<<set.io_number);
164 else if ( set.mode_data == DIO_LOW )
165 do_state_keep &= ~(1<<set.io_number);
166 else
167 return -EINVAL;
168 outb(do_state_keep, do_addr);
169 break;
170 case IOCTL_GET_DOUT :
171 case IOCTL_GET_DIN :
172 if ( copy_from_user(&set, (struct dio_set_struct *)arg, sizeof(struct dio_set_struct)) )
173 return -EFAULT;
174 if ( set.io_number < 0 || set.io_number >= MAX_DIO )
175 return -EINVAL;
176 if ( cmd == IOCTL_GET_DOUT ) {
177 if ( do_state_keep & (1<<set.io_number) )
178 set.mode_data = 1;
179 else
180 set.mode_data = 0;
181 } else {
182 di_state = inb(di_addr);
183 if ( di_state & (1<<(set.io_number+4)) )
184 set.mode_data = 1;
185 else
186 set.mode_data = 0;
188 if ( copy_to_user((struct dio_set_struct *)arg, &set, sizeof(struct dio_set_struct)) )
189 return -EFAULT;
190 break;
191 default:
192 return -EINVAL;
194 return 0;
197 static int dio_open(struct inode *inode, struct file *file)
199 if ( MINOR(inode->i_rdev) == MOXA_DIO_MINOR )
200 return 0;
202 return -ENODEV;
205 static int dio_release(struct inode *inode, struct file *file)
207 return 0;
210 static struct file_operations dio_fops = {
211 owner:THIS_MODULE,
212 llseek:NULL,
213 ioctl:dio_ioctl,
214 open:dio_open,
215 release:dio_release,
218 static struct miscdevice dio_dev = {
219 MOXA_DIO_MINOR,
220 "dio1",
221 &dio_fops
224 static void __exit dio_exit(void)
226 remove_proc_entry(dio_proc_name,0);
227 misc_deregister(&dio_dev);
228 iounmap((void *)di_addr);
229 iounmap((void *)do_addr);
232 static int __init dio_init(void)
234 printk("Moxa W325 Register DI/DO misc ver1.0 ");
236 di_addr=(unsigned long) ioremap((unsigned long)DI_PADDR, 0x4000);
237 do_addr=(unsigned long) ioremap((unsigned long)DO_PADDR, 0x4000);
239 if ( di_addr==NULL || do_addr==NULL || misc_register(&dio_dev) ) {
240 printk("fail !\n");
241 return -ENOMEM;
244 outb(do_state_keep, do_addr);
245 dio_proc = create_proc_entry(dio_proc_name, 0, NULL);
246 dio_proc->read_proc = dio_read_proc;
247 dio_proc->write_proc = dio_write_proc;
249 printk("OK.\n");
250 return 0;
253 module_init(dio_init);
254 module_exit(dio_exit);
256 MODULE_AUTHOR("Victor Yu");
257 MODULE_LICENSE("GPL");