blob: f1a93347563b788c89541fd2c834b1c6d75d98fc [file] [log] [blame]
Ravi Kumar Vd4cb56c2012-03-22 19:04:13 +05301/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/ioctl.h>
16#include <linux/fs.h>
17#include <linux/poll.h>
18#include <linux/platform_device.h>
19#include <linux/device.h>
20#include <linux/cdev.h>
21#include <linux/slab.h>
22
23#include <media/rc-core.h>
24#include <media/user-rc-input.h>
25
26#define MAX_RC_DEVICES 1
27#define USER_RC_INPUT_DEV_NAME "user-rc-input"
28#define USER_RC_INPUT_DRV_NAME "rc-user-input"
29
30struct user_rc_input_dev {
31 struct cdev rc_input_cdev;
32 struct class *rc_input_class;
33 struct device *rc_input_dev;
34 struct rc_dev *rcdev;
35 dev_t rc_input_base_dev;
36 struct device *dev;
37 int in_use;
38};
39
40static int user_rc_input_open(struct inode *inode, struct file *file)
41{
42 struct cdev *input_cdev = inode->i_cdev;
43 struct user_rc_input_dev *input_dev =
44 container_of(input_cdev, struct user_rc_input_dev, rc_input_cdev);
45
46 if (input_dev->in_use) {
47 dev_err(input_dev->dev,
48 "Device is already open..only one instance is allowed\n");
49 return -EBUSY;
50 }
51 input_dev->in_use++;
52 file->private_data = input_dev;
53
54 return 0;
55}
56
57static int user_rc_input_release(struct inode *inode, struct file *file)
58{
59 struct user_rc_input_dev *input_dev = file->private_data;
60
61 input_dev->in_use--;
62
63 return 0;
64}
65
66static ssize_t user_rc_input_write(struct file *file, const char __user *buffer,
67 size_t count, loff_t *ppos)
68{
69 int ret;
70 struct user_rc_input_dev *input_dev = file->private_data;
71 __u8 *buf;
72
73 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
74 if (!buf) {
75 dev_err(input_dev->dev,
76 "kmalloc failed...Insufficient memory\n");
77 ret = -ENOMEM;
78 goto out;
79 }
80
81 if (copy_from_user(buf, buffer, count)) {
82 dev_err(input_dev->dev, "Copy from user failed\n");
83 ret = -EFAULT;
84 goto out_free;
85 }
86
87 switch (buf[0]) {
88 case USER_CONTROL_PRESSED:
89 dev_dbg(input_dev->dev, "user controlled"
90 " pressed 0x%x\n", buf[1]);
91 rc_keydown(input_dev->rcdev, buf[1], 0);
92 break;
93 case USER_CONTROL_REPEATED:
94 dev_dbg(input_dev->dev, "user controlled"
95 " repeated 0x%x\n", buf[1]);
96 rc_repeat(input_dev->rcdev);
97 break;
98 case USER_CONTROL_RELEASED:
99 dev_dbg(input_dev->dev, "user controlled"
100 " released 0x%x\n", buf[1]);
101 rc_keyup(input_dev->rcdev);
102 break;
103 }
104
105out_free:
106 kfree(buf);
107out:
108 return ret;
109}
110
111const struct file_operations fops = {
112 .owner = THIS_MODULE,
113 .open = user_rc_input_open,
114 .write = user_rc_input_write,
115 .release = user_rc_input_release,
116};
117
118static int __devinit user_rc_input_probe(struct platform_device *pdev)
119{
120 struct user_rc_input_dev *user_rc_dev;
121 struct rc_dev *rcdev;
122 int retval;
123
124 user_rc_dev = kzalloc(sizeof(struct user_rc_input_dev), GFP_KERNEL);
125 if (!user_rc_dev)
126 return -ENOMEM;
127
128 user_rc_dev->rc_input_class = class_create(THIS_MODULE,
129 "user-rc-input-loopback");
130
131 if (IS_ERR(user_rc_dev->rc_input_class)) {
132 retval = PTR_ERR(user_rc_dev->rc_input_class);
133 goto err;
134 }
135
136 retval = alloc_chrdev_region(&user_rc_dev->rc_input_base_dev, 0,
137 MAX_RC_DEVICES, USER_RC_INPUT_DEV_NAME);
138
139 if (retval) {
140 dev_err(&pdev->dev,
141 "alloc_chrdev_region failed\n");
142 goto alloc_chrdev_err;
143 }
144
145 dev_info(&pdev->dev, "User space report key event input "
146 "loopback driver registered, "
147 "major %d\n", MAJOR(user_rc_dev->rc_input_base_dev));
148
149 cdev_init(&user_rc_dev->rc_input_cdev, &fops);
150 retval = cdev_add(&user_rc_dev->rc_input_cdev,
151 user_rc_dev->rc_input_base_dev,
152 MAX_RC_DEVICES);
153 if (retval) {
154 dev_err(&pdev->dev, "cdev_add failed\n");
155 goto cdev_add_err;
156 }
157 user_rc_dev->rc_input_dev =
158 device_create(user_rc_dev->rc_input_class,
159 NULL,
160 MKDEV(MAJOR(user_rc_dev->rc_input_base_dev),
161 0), NULL, "user-rc-input-dev%d", 0);
162
163 if (IS_ERR(user_rc_dev->rc_input_dev)) {
164 retval = PTR_ERR(user_rc_dev->rc_input_dev);
165 dev_err(&pdev->dev, "device_create failed\n");
166 goto device_create_err;
167 }
168
169 rcdev = rc_allocate_device();
170 if (!rcdev) {
171 dev_err(&pdev->dev, "failed to allocate rc device");
172 retval = -ENOMEM;
173 goto err_allocate_device;
174 }
175
176 rcdev->driver_type = RC_DRIVER_SCANCODE;
177 rcdev->allowed_protos = RC_TYPE_OTHER;
178 rcdev->input_name = USER_RC_INPUT_DEV_NAME;
179 rcdev->input_id.bustype = BUS_HOST;
180 rcdev->driver_name = USER_RC_INPUT_DRV_NAME;
181 rcdev->map_name = RC_MAP_UE_RF4CE;
182
183 retval = rc_register_device(rcdev);
184 if (retval < 0) {
185 dev_err(&pdev->dev, "failed to register rc device\n");
186 goto rc_register_err;
187 }
188 user_rc_dev->rcdev = rcdev;
189 user_rc_dev->dev = &pdev->dev;
190 platform_set_drvdata(pdev, user_rc_dev);
191 user_rc_dev->in_use = 0;
192
193 return 0;
194
195rc_register_err:
196 rc_free_device(rcdev);
197err_allocate_device:
198 device_destroy(user_rc_dev->rc_input_class,
199 MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
200cdev_add_err:
201 unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
202 MAX_RC_DEVICES);
203device_create_err:
204 cdev_del(&user_rc_dev->rc_input_cdev);
205alloc_chrdev_err:
206 class_destroy(user_rc_dev->rc_input_class);
207err:
208 kfree(user_rc_dev);
209 return retval;
210}
211
212static int __devexit user_rc_input_remove(struct platform_device *pdev)
213{
214 struct user_rc_input_dev *user_rc_dev = platform_get_drvdata(pdev);
215
216 platform_set_drvdata(pdev, NULL);
217 rc_free_device(user_rc_dev->rcdev);
218 device_destroy(user_rc_dev->rc_input_class,
219 MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
220 unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
221 MAX_RC_DEVICES);
222 cdev_del(&user_rc_dev->rc_input_cdev);
223 class_destroy(user_rc_dev->rc_input_class);
224 kfree(user_rc_dev);
225
226 return 0;
227}
228
229static struct platform_driver user_rc_input_driver = {
230 .probe = user_rc_input_probe,
231 .remove = __devexit_p(user_rc_input_remove),
232 .driver = {
233 .name = USER_RC_INPUT_DRV_NAME,
234 .owner = THIS_MODULE,
235 },
236};
237
238static int __init user_rc_input_init(void)
239{
240 return platform_driver_register(&user_rc_input_driver);
241}
242module_init(user_rc_input_init);
243
244static void __exit user_rc_input_exit(void)
245{
246 platform_driver_unregister(&user_rc_input_driver);
247}
248module_exit(user_rc_input_exit);
249
250MODULE_DESCRIPTION("User RC Input driver");
251MODULE_LICENSE("GPL v2");