Commit | Line | Data |
---|---|---|
00e8c494 | 1 | /* |
2 | * arch/sh/boards/landisk/gio.c - driver for landisk | |
3 | * | |
4 | * This driver will also support the I-O DATA Device, Inc. LANDISK Board. | |
5 | * LANDISK and USL-5P Button, LED and GIO driver drive function. | |
6 | * | |
7 | * Copylight (C) 2006 kogiidena | |
8 | * Copylight (C) 2002 Atom Create Engineering Co., Ltd. * | |
9 | * | |
10 | * This file is subject to the terms and conditions of the GNU General Public | |
11 | * License. See the file "COPYING" in the main directory of this archive | |
12 | * for more details. | |
13 | * | |
14 | */ | |
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
1fa984b5 | 17 | #include <linux/smp_lock.h> |
00e8c494 | 18 | #include <linux/kdev_t.h> |
19 | #include <linux/cdev.h> | |
20 | #include <linux/fs.h> | |
21 | #include <asm/io.h> | |
22 | #include <asm/uaccess.h> | |
0764bff4 PM |
23 | #include <mach-landisk/mach/gio.h> |
24 | #include <mach-landisk/mach/iodata_landisk.h> | |
00e8c494 | 25 | |
26 | #define DEVCOUNT 4 | |
27 | #define GIO_MINOR 2 /* GIO minor no. */ | |
28 | ||
29 | static dev_t dev; | |
30 | static struct cdev *cdev_p; | |
31 | static int openCnt; | |
32 | ||
33 | static int gio_open(struct inode *inode, struct file *filp) | |
34 | { | |
35 | int minor; | |
1fa984b5 | 36 | int ret = -ENOENT; |
00e8c494 | 37 | |
1fa984b5 | 38 | lock_kernel(); |
00e8c494 | 39 | minor = MINOR(inode->i_rdev); |
40 | if (minor < DEVCOUNT) { | |
41 | if (openCnt > 0) { | |
1fa984b5 | 42 | ret = -EALREADY; |
00e8c494 | 43 | } else { |
44 | openCnt++; | |
1fa984b5 | 45 | ret = 0; |
00e8c494 | 46 | } |
47 | } | |
1fa984b5 JC |
48 | unlock_kernel(); |
49 | return ret; | |
00e8c494 | 50 | } |
51 | ||
52 | static int gio_close(struct inode *inode, struct file *filp) | |
53 | { | |
54 | int minor; | |
55 | ||
56 | minor = MINOR(inode->i_rdev); | |
57 | if (minor < DEVCOUNT) { | |
58 | openCnt--; | |
59 | } | |
60 | return 0; | |
61 | } | |
62 | ||
63 | static int gio_ioctl(struct inode *inode, struct file *filp, | |
64 | unsigned int cmd, unsigned long arg) | |
65 | { | |
66 | unsigned int data; | |
67 | static unsigned int addr = 0; | |
68 | ||
69 | if (cmd & 0x01) { /* write */ | |
70 | if (copy_from_user(&data, (int *)arg, sizeof(int))) { | |
71 | return -EFAULT; | |
72 | } | |
73 | } | |
74 | ||
75 | switch (cmd) { | |
e868d612 | 76 | case GIODRV_IOCSGIOSETADDR: /* address set */ |
00e8c494 | 77 | addr = data; |
78 | break; | |
79 | ||
80 | case GIODRV_IOCSGIODATA1: /* write byte */ | |
81 | ctrl_outb((unsigned char)(0x0ff & data), addr); | |
82 | break; | |
83 | ||
84 | case GIODRV_IOCSGIODATA2: /* write word */ | |
85 | if (addr & 0x01) { | |
86 | return -EFAULT; | |
87 | } | |
88 | ctrl_outw((unsigned short int)(0x0ffff & data), addr); | |
89 | break; | |
90 | ||
91 | case GIODRV_IOCSGIODATA4: /* write long */ | |
92 | if (addr & 0x03) { | |
93 | return -EFAULT; | |
94 | } | |
95 | ctrl_outl(data, addr); | |
96 | break; | |
97 | ||
98 | case GIODRV_IOCGGIODATA1: /* read byte */ | |
99 | data = ctrl_inb(addr); | |
100 | break; | |
101 | ||
102 | case GIODRV_IOCGGIODATA2: /* read word */ | |
103 | if (addr & 0x01) { | |
104 | return -EFAULT; | |
105 | } | |
106 | data = ctrl_inw(addr); | |
107 | break; | |
108 | ||
109 | case GIODRV_IOCGGIODATA4: /* read long */ | |
110 | if (addr & 0x03) { | |
111 | return -EFAULT; | |
112 | } | |
113 | data = ctrl_inl(addr); | |
114 | break; | |
115 | default: | |
116 | return -EFAULT; | |
117 | break; | |
118 | } | |
119 | ||
120 | if ((cmd & 0x01) == 0) { /* read */ | |
121 | if (copy_to_user((int *)arg, &data, sizeof(int))) { | |
122 | return -EFAULT; | |
123 | } | |
124 | } | |
125 | return 0; | |
126 | } | |
127 | ||
773c7bd6 | 128 | static const struct file_operations gio_fops = { |
00e8c494 | 129 | .owner = THIS_MODULE, |
130 | .open = gio_open, /* open */ | |
131 | .release = gio_close, /* release */ | |
132 | .ioctl = gio_ioctl, /* ioctl */ | |
133 | }; | |
134 | ||
135 | static int __init gio_init(void) | |
136 | { | |
137 | int error; | |
138 | ||
139 | printk(KERN_INFO "gio: driver initialized\n"); | |
140 | ||
141 | openCnt = 0; | |
142 | ||
143 | if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) { | |
144 | printk(KERN_ERR | |
145 | "gio: Couldn't alloc_chrdev_region, error=%d\n", | |
146 | error); | |
147 | return 1; | |
148 | } | |
149 | ||
150 | cdev_p = cdev_alloc(); | |
151 | cdev_p->ops = &gio_fops; | |
152 | error = cdev_add(cdev_p, dev, DEVCOUNT); | |
153 | if (error) { | |
154 | printk(KERN_ERR | |
155 | "gio: Couldn't cdev_add, error=%d\n", error); | |
156 | return 1; | |
157 | } | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | static void __exit gio_exit(void) | |
163 | { | |
164 | cdev_del(cdev_p); | |
165 | unregister_chrdev_region(dev, DEVCOUNT); | |
166 | } | |
167 | ||
168 | module_init(gio_init); | |
169 | module_exit(gio_exit); | |
170 | ||
171 | MODULE_LICENSE("GPL"); |