blob: 78afacebf4831ba07b540f5ca63be17f9fcd91d0 [file] [log] [blame]
Flemmardce3c2c32013-05-23 16:53:44 -07001/*
2 * Copyright (c) 2011 Synaptics Incorporated
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/fs.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <linux/slab.h>
23#include <linux/input.h>
24#include <linux/interrupt.h>
25#include <linux/syscalls.h>
26#include <linux/i2c.h>
27#include <linux/rmi.h>
28
29#define CHAR_DEVICE_NAME "rmi"
30
31#define REG_ADDR_LIMIT 0xFFFF
32
33static int rmi_char_dev_major_num;
34
35
36
37static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
38{
39 loff_t newpos;
40 struct rmi_char_dev *my_char_dev = filp->private_data;
41
42 if (IS_ERR(my_char_dev)) {
43 pr_err("%s: pointer of char device is invalid", __func__);
44 return -EBADF;
45 }
46
47 mutex_lock(&(my_char_dev->mutex_file_op));
48
49 switch (whence) {
50 case SEEK_SET:
51 newpos = off;
52 break;
53
54 case SEEK_CUR:
55 newpos = filp->f_pos + off;
56 break;
57
58 case SEEK_END:
59 newpos = REG_ADDR_LIMIT + off;
60 break;
61
62 default:
63 newpos = -EINVAL;
64 goto clean_up;
65 }
66
67 if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
68 dev_err(my_char_dev->phys->dev, "newpos 0x%04x is invalid.\n",
69 (unsigned int)newpos);
70 newpos = -EINVAL;
71 goto clean_up;
72 }
73
74 filp->f_pos = newpos;
75
76clean_up:
77 mutex_unlock(&(my_char_dev->mutex_file_op));
78 return newpos;
79}
80
81static ssize_t rmi_char_dev_read(struct file *filp, char __user *buf,
82 size_t count, loff_t *f_pos)
83{
84 struct rmi_char_dev *my_char_dev = filp->private_data;
85 ssize_t ret_value = 0;
86 unsigned char tmpbuf[count+1];
87
88
89
90 if (count > (REG_ADDR_LIMIT - *f_pos))
91 count = REG_ADDR_LIMIT - *f_pos;
92
93 if (count == 0)
94 return 0;
95
96 if (IS_ERR(my_char_dev)) {
97 pr_err("%s: pointer of char device is invalid", __func__);
98 ret_value = -EBADF;
99 return ret_value;
100 }
101
102 mutex_lock(&(my_char_dev->mutex_file_op));
103
104
105
106
107 ret_value = i2c_rmi_read(*f_pos, tmpbuf, count);
108
109
110 if (ret_value < 0)
111 goto clean_up;
112 else
113 *f_pos += ret_value;
114
115 if (copy_to_user(buf, tmpbuf, count))
116 ret_value = -EFAULT;
117
118clean_up:
119
120 mutex_unlock(&(my_char_dev->mutex_file_op));
121
122 return ret_value;
123}
124
125static ssize_t rmi_char_dev_write(struct file *filp, const char __user *buf,
126 size_t count, loff_t *f_pos)
127{
128 struct rmi_char_dev *my_char_dev = filp->private_data;
129 ssize_t ret_value = 0;
130 unsigned char tmpbuf[count+1];
131
132
133
134 if (count > (REG_ADDR_LIMIT - *f_pos))
135 count = REG_ADDR_LIMIT - *f_pos;
136
137 if (count == 0)
138 return 0;
139
140 if (IS_ERR(my_char_dev)) {
141 pr_err("%s: pointer of char device is invalid", __func__);
142 ret_value = -EBADF;
143 return ret_value;
144 }
145
146 if (copy_from_user(tmpbuf, buf, count)) {
147 ret_value = -EFAULT;
148 return ret_value;
149 }
150
151 mutex_lock(&(my_char_dev->mutex_file_op));
152
153
154
155
156 ret_value = i2c_rmi_write(*f_pos, tmpbuf, count);
157
158 if (ret_value >= 0)
159 *f_pos += count;
160
161 mutex_unlock(&(my_char_dev->mutex_file_op));
162
163 return ret_value;
164}
165
166static int rmi_char_dev_open(struct inode *inp, struct file *filp)
167{
168
169 struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
170 struct rmi_char_dev, main_dev);
171
172 int ret_value = 0;
173
174 filp->private_data = my_dev;
175
176
177
178
179 mutex_lock(&(my_dev->mutex_file_op));
180 if (my_dev->ref_count < 1)
181 my_dev->ref_count++;
182 else
183 ret_value = -EACCES;
184
185 mutex_unlock(&(my_dev->mutex_file_op));
186
187 return ret_value;
188}
189
190static int rmi_char_dev_release(struct inode *inp, struct file *filp)
191{
192 struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
193 struct rmi_char_dev, main_dev);
194
195 mutex_lock(&(my_dev->mutex_file_op));
196
197 my_dev->ref_count--;
198 if (my_dev->ref_count < 0)
199 my_dev->ref_count = 0;
200
201 mutex_unlock(&(my_dev->mutex_file_op));
202
203 return 0;
204}
205
206static const struct file_operations rmi_char_dev_fops = {
207 .owner = THIS_MODULE,
208 .llseek = rmi_char_dev_llseek,
209 .read = rmi_char_dev_read,
210 .write = rmi_char_dev_write,
211 .open = rmi_char_dev_open,
212 .release = rmi_char_dev_release,
213};
214
215static void rmi_char_dev_clean_up(struct rmi_char_dev *char_dev,
216 struct class *char_device_class)
217{
218 dev_t devno;
219
220
221 if (char_dev) {
222 devno = char_dev->main_dev.dev;
223
224 cdev_del(&char_dev->main_dev);
225 kfree(char_dev);
226
227 if (char_device_class) {
228 device_destroy(char_device_class, devno);
229 class_unregister(char_device_class);
230 class_destroy(char_device_class);
231 }
232
233
234 unregister_chrdev_region(devno, 1);
235 pr_debug("%s: rmi_char_dev is removed\n", __func__);
236 }
237}
238
239static char *rmi_char_devnode(struct device *dev, mode_t *mode)
240{
241 if (!mode)
242 return NULL;
243
244
245 *mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
246
247 return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
248}
249
250int rmi_char_dev_register(void)
251{
252 struct rmi_char_dev *char_dev;
253 dev_t dev_no;
254 int err;
255 int result;
256 struct device *device_ptr;
257 struct class *rmi_char_device_class;
258
259 if (rmi_char_dev_major_num) {
260 dev_no = MKDEV(rmi_char_dev_major_num, 0);
261 result = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
262 } else {
263 result = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
264
265 rmi_char_dev_major_num = MAJOR(dev_no);
266 printk(KERN_ERR "Major number of rmi_char_dev: %d\n",
267 rmi_char_dev_major_num);
268 }
269 if (result < 0)
270 return result;
271
272 char_dev = kzalloc(sizeof(struct rmi_char_dev), GFP_KERNEL);
273 if (!char_dev) {
274 printk(KERN_ERR "Failed to allocate rmi_char_dev.\n");
275
276 __unregister_chrdev(rmi_char_dev_major_num, MINOR(dev_no), 1,
277 CHAR_DEVICE_NAME);
278 return -ENOMEM;
279 }
280
281 mutex_init(&char_dev->mutex_file_op);
282
283
284 cdev_init(&char_dev->main_dev, &rmi_char_dev_fops);
285
286 err = cdev_add(&char_dev->main_dev, dev_no, 1);
287 if (err) {
288 printk(KERN_ERR "Error %d adding rmi_char_dev.\n", err);
289
290
291 return err;
292 }
293
294
295 rmi_char_device_class =
296 class_create(THIS_MODULE, CHAR_DEVICE_NAME);
297
298 if (IS_ERR(rmi_char_device_class)) {
299 printk(KERN_INFO "Failed to create /dev/%s.\n",
300 CHAR_DEVICE_NAME);
301 rmi_char_dev_clean_up(char_dev,
302 rmi_char_device_class);
303 return -ENODEV;
304 }
305
306 rmi_char_device_class->devnode = rmi_char_devnode;
307
308
309 device_ptr = device_create(
310 rmi_char_device_class,
311 NULL, dev_no, NULL,
312 CHAR_DEVICE_NAME"%d",
313 MINOR(dev_no));
314
315 if (IS_ERR(device_ptr)) {
316 printk(KERN_ERR "Failed to create rmi device.\n");
317 rmi_char_dev_clean_up(char_dev,
318 rmi_char_device_class);
319 return -ENODEV;
320 }
321
322 return 0;
323}
324EXPORT_SYMBOL(rmi_char_dev_register);
325
326
327void rmi_char_dev_unregister(struct rmi_phys_device *phys)
328{
329
330 if (phys)
331 rmi_char_dev_clean_up(phys->char_dev,
332 phys->rmi_char_device_class);
333}
334EXPORT_SYMBOL(rmi_char_dev_unregister);
335
336MODULE_AUTHOR("Synaptics, Inc.");
337MODULE_DESCRIPTION("RMI4 Char Device");
338MODULE_LICENSE("GPL");