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> | |
17 | #include <linux/kdev_t.h> | |
18 | #include <linux/cdev.h> | |
19 | #include <linux/fs.h> | |
20 | #include <asm/io.h> | |
21 | #include <asm/uaccess.h> | |
0764bff4 PM |
22 | #include <mach-landisk/mach/gio.h> |
23 | #include <mach-landisk/mach/iodata_landisk.h> | |
00e8c494 | 24 | |
25 | #define DEVCOUNT 4 | |
26 | #define GIO_MINOR 2 /* GIO minor no. */ | |
27 | ||
28 | static dev_t dev; | |
29 | static struct cdev *cdev_p; | |
30 | static int openCnt; | |
31 | ||
32 | static int gio_open(struct inode *inode, struct file *filp) | |
33 | { | |
34 | int minor; | |
1fa984b5 | 35 | int ret = -ENOENT; |
00e8c494 | 36 | |
52a94909 | 37 | preempt_disable(); |
00e8c494 | 38 | minor = MINOR(inode->i_rdev); |
39 | if (minor < DEVCOUNT) { | |
40 | if (openCnt > 0) { | |
1fa984b5 | 41 | ret = -EALREADY; |
00e8c494 | 42 | } else { |
43 | openCnt++; | |
1fa984b5 | 44 | ret = 0; |
00e8c494 | 45 | } |
46 | } | |
52a94909 | 47 | preempt_enable(); |
1fa984b5 | 48 | return ret; |
00e8c494 | 49 | } |
50 | ||
51 | static int gio_close(struct inode *inode, struct file *filp) | |
52 | { | |
53 | int minor; | |
54 | ||
55 | minor = MINOR(inode->i_rdev); | |
56 | if (minor < DEVCOUNT) { | |
57 | openCnt--; | |
58 | } | |
59 | return 0; | |
60 | } | |
61 | ||
52a94909 | 62 | static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
00e8c494 | 63 | { |
64 | unsigned int data; | |
65 | static unsigned int addr = 0; | |
66 | ||
67 | if (cmd & 0x01) { /* write */ | |
68 | if (copy_from_user(&data, (int *)arg, sizeof(int))) { | |
69 | return -EFAULT; | |
70 | } | |
71 | } | |
72 | ||
73 | switch (cmd) { | |
e868d612 | 74 | case GIODRV_IOCSGIOSETADDR: /* address set */ |
00e8c494 | 75 | addr = data; |
76 | break; | |
77 | ||
78 | case GIODRV_IOCSGIODATA1: /* write byte */ | |
9d56dd3b | 79 | __raw_writeb((unsigned char)(0x0ff & data), addr); |
00e8c494 | 80 | break; |
81 | ||
82 | case GIODRV_IOCSGIODATA2: /* write word */ | |
83 | if (addr & 0x01) { | |
84 | return -EFAULT; | |
85 | } | |
9d56dd3b | 86 | __raw_writew((unsigned short int)(0x0ffff & data), addr); |
00e8c494 | 87 | break; |
88 | ||
89 | case GIODRV_IOCSGIODATA4: /* write long */ | |
90 | if (addr & 0x03) { | |
91 | return -EFAULT; | |
92 | } | |
9d56dd3b | 93 | __raw_writel(data, addr); |
00e8c494 | 94 | break; |
95 | ||
96 | case GIODRV_IOCGGIODATA1: /* read byte */ | |
9d56dd3b | 97 | data = __raw_readb(addr); |
00e8c494 | 98 | break; |
99 | ||
100 | case GIODRV_IOCGGIODATA2: /* read word */ | |
101 | if (addr & 0x01) { | |
102 | return -EFAULT; | |
103 | } | |
9d56dd3b | 104 | data = __raw_readw(addr); |
00e8c494 | 105 | break; |
106 | ||
107 | case GIODRV_IOCGGIODATA4: /* read long */ | |
108 | if (addr & 0x03) { | |
109 | return -EFAULT; | |
110 | } | |
9d56dd3b | 111 | data = __raw_readl(addr); |
00e8c494 | 112 | break; |
113 | default: | |
114 | return -EFAULT; | |
115 | break; | |
116 | } | |
117 | ||
118 | if ((cmd & 0x01) == 0) { /* read */ | |
119 | if (copy_to_user((int *)arg, &data, sizeof(int))) { | |
120 | return -EFAULT; | |
121 | } | |
122 | } | |
123 | return 0; | |
124 | } | |
125 | ||
773c7bd6 | 126 | static const struct file_operations gio_fops = { |
00e8c494 | 127 | .owner = THIS_MODULE, |
128 | .open = gio_open, /* open */ | |
129 | .release = gio_close, /* release */ | |
52a94909 | 130 | .unlocked_ioctl = gio_ioctl, |
6038f373 | 131 | .llseek = noop_llseek, |
00e8c494 | 132 | }; |
133 | ||
134 | static int __init gio_init(void) | |
135 | { | |
136 | int error; | |
137 | ||
138 | printk(KERN_INFO "gio: driver initialized\n"); | |
139 | ||
140 | openCnt = 0; | |
141 | ||
142 | if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) { | |
143 | printk(KERN_ERR | |
144 | "gio: Couldn't alloc_chrdev_region, error=%d\n", | |
145 | error); | |
146 | return 1; | |
147 | } | |
148 | ||
149 | cdev_p = cdev_alloc(); | |
150 | cdev_p->ops = &gio_fops; | |
151 | error = cdev_add(cdev_p, dev, DEVCOUNT); | |
152 | if (error) { | |
153 | printk(KERN_ERR | |
154 | "gio: Couldn't cdev_add, error=%d\n", error); | |
155 | return 1; | |
156 | } | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
161 | static void __exit gio_exit(void) | |
162 | { | |
163 | cdev_del(cdev_p); | |
164 | unregister_chrdev_region(dev, DEVCOUNT); | |
165 | } | |
166 | ||
167 | module_init(gio_init); | |
168 | module_exit(gio_exit); | |
169 | ||
170 | MODULE_LICENSE("GPL"); |