blob: 83da95df1e07e133611c351ad4f9253366d909c2 [file] [log] [blame]
Bamidi RaviKiran206ddb62012-10-08 09:53:56 +05301/* Copyright (c) 2012, The Linux Foundation. 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
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/ioctl.h>
17#include <linux/fs.h>
18#include <linux/uaccess.h>
19#include <linux/platform_device.h>
20#include <linux/device.h>
21#include <linux/cdev.h>
22#include <linux/slab.h>
23
24#include <media/rc-core.h>
25#include <media/user-rc-input.h>
26
27#define MAX_SP_DEVICES 1
28#define USER_SP_INPUT_DEV_NAME "user-sp-input"
29#define USER_SP_INPUT_DRV_NAME "sp-user-input"
30
31struct user_sp_input_dev {
32 struct cdev sp_input_cdev;
33 struct class *sp_input_class;
34 struct device *sp_input_dev;
35 struct rc_dev *spdev;
36 dev_t sp_input_base_dev;
37 struct device *dev;
38 int in_use;
39};
40
41static int user_sp_input_open(struct inode *inode, struct file *file)
42{
43 struct cdev *input_cdev = inode->i_cdev;
44 struct user_sp_input_dev *input_dev =
45 container_of(input_cdev, struct user_sp_input_dev, sp_input_cdev);
46
47 if (input_dev->in_use) {
48 dev_err(input_dev->dev,
49 "Device is already open..only one instance is allowed\n");
50 return -EBUSY;
51 }
52 input_dev->in_use++;
53 file->private_data = input_dev;
54
55 return 0;
56}
57
58static int user_sp_input_release(struct inode *inode, struct file *file)
59{
60 struct user_sp_input_dev *input_dev = file->private_data;
61
62 input_dev->in_use--;
63
64 return 0;
65}
66
67static ssize_t user_sp_input_write(struct file *file,
68 const char __user *buffer, size_t count, loff_t *ppos)
69{
70 int ret = count;
71 struct user_sp_input_dev *input_dev = file->private_data;
72 unsigned char cmd = 0;
73 int scancode = 0;
74
75 if (copy_from_user(&cmd, buffer, 1)) {
76 dev_err(input_dev->dev, "Copy from user failed\n");
77 ret = -EFAULT;
78 goto out_free;
79 }
80
81 if (copy_from_user(&scancode, &buffer[1], 4)) {
82 dev_err(input_dev->dev, "Copy from user failed\n");
83 ret = -EFAULT;
84 goto out_free;
85 }
86
87 switch (cmd) {
88 case USER_CONTROL_PRESSED:
89 dev_dbg(input_dev->dev, "user controlled pressed 0x%x\n",
90 scancode);
91 rc_keydown(input_dev->spdev, scancode, 0);
92 break;
93 case USER_CONTROL_REPEATED:
94 dev_dbg(input_dev->dev, "user controlled repeated 0x%x\n",
95 scancode);
96 rc_repeat(input_dev->spdev);
97 break;
98 case USER_CONTROL_RELEASED:
99 dev_dbg(input_dev->dev, "user controlled released 0x%x\n",
100 scancode);
101 rc_keyup(input_dev->spdev);
102 break;
103 }
104
105out_free:
106 return ret;
107}
108
109const struct file_operations sp_fops = {
110 .owner = THIS_MODULE,
111 .open = user_sp_input_open,
112 .write = user_sp_input_write,
113 .release = user_sp_input_release,
114};
115
116static int __devinit user_sp_input_probe(struct platform_device *pdev)
117{
118 struct user_sp_input_dev *user_sp_dev;
119 struct rc_dev *spdev;
120 int retval;
121
122 user_sp_dev = kzalloc(sizeof(struct user_sp_input_dev), GFP_KERNEL);
123 if (!user_sp_dev)
124 return -ENOMEM;
125
126 user_sp_dev->sp_input_class = class_create(THIS_MODULE,
127 "user-sp-input-loopback");
128
129 if (IS_ERR(user_sp_dev->sp_input_class)) {
130 retval = PTR_ERR(user_sp_dev->sp_input_class);
131 goto err;
132 }
133
134 retval = alloc_chrdev_region(&user_sp_dev->sp_input_base_dev, 0,
135 MAX_SP_DEVICES, USER_SP_INPUT_DEV_NAME);
136
137 if (retval) {
138 dev_err(&pdev->dev,
139 "alloc_chrdev_region failed\n");
140 goto alloc_chrdev_err;
141 }
142
143 dev_info(&pdev->dev, "User space report standby key event input" \
144 " driver registered, major %d\n",
145 MAJOR(user_sp_dev->sp_input_base_dev));
146
147 cdev_init(&user_sp_dev->sp_input_cdev, &sp_fops);
148 retval = cdev_add(&user_sp_dev->sp_input_cdev,
149 user_sp_dev->sp_input_base_dev, MAX_SP_DEVICES);
150 if (retval) {
151 dev_err(&pdev->dev, "cdev_add failed\n");
152 goto cdev_add_err;
153 }
154 user_sp_dev->sp_input_dev = device_create(user_sp_dev->sp_input_class,
155 NULL, MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0), NULL,
156 "user-sp-input-dev%d", 0);
157
158 if (IS_ERR(user_sp_dev->sp_input_dev)) {
159 retval = PTR_ERR(user_sp_dev->sp_input_dev);
160 dev_err(&pdev->dev, "device_create failed\n");
161 goto device_create_err;
162 }
163
164 spdev = rc_allocate_device();
165 if (!spdev) {
166 dev_err(&pdev->dev, "failed to allocate rc device");
167 retval = -ENOMEM;
168 goto err_allocate_device;
169 }
170
171 spdev->driver_type = RC_DRIVER_SCANCODE;
172 spdev->allowed_protos = RC_TYPE_OTHER;
173 spdev->input_name = USER_SP_INPUT_DEV_NAME;
174 spdev->input_id.bustype = BUS_HOST;
175 spdev->driver_name = USER_SP_INPUT_DRV_NAME;
176 spdev->map_name = RC_MAP_RC6_PHILIPS;
177
178 retval = rc_register_device(spdev);
179 if (retval < 0) {
180 dev_err(&pdev->dev, "failed to register rc device\n");
181 goto rc_register_err;
182 }
183 user_sp_dev->spdev = spdev;
184 user_sp_dev->dev = &pdev->dev;
185 platform_set_drvdata(pdev, user_sp_dev);
186 user_sp_dev->in_use = 0;
187
188 return 0;
189
190rc_register_err:
191 rc_free_device(spdev);
192err_allocate_device:
193 device_destroy(user_sp_dev->sp_input_class,
194 MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0));
195cdev_add_err:
196 unregister_chrdev_region(user_sp_dev->sp_input_base_dev,
197 MAX_SP_DEVICES);
198device_create_err:
199 cdev_del(&user_sp_dev->sp_input_cdev);
200alloc_chrdev_err:
201 class_destroy(user_sp_dev->sp_input_class);
202err:
203 kfree(user_sp_dev);
204 return retval;
205}
206
207static int __devexit user_sp_input_remove(struct platform_device *pdev)
208{
209 struct user_sp_input_dev *user_sp_dev = platform_get_drvdata(pdev);
210
211 platform_set_drvdata(pdev, NULL);
212 rc_free_device(user_sp_dev->spdev);
213 device_destroy(user_sp_dev->sp_input_class,
214 MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0));
215 unregister_chrdev_region(user_sp_dev->sp_input_base_dev,
216 MAX_SP_DEVICES);
217 cdev_del(&user_sp_dev->sp_input_cdev);
218 class_destroy(user_sp_dev->sp_input_class);
219 kfree(user_sp_dev);
220
221 return 0;
222}
223
224static struct platform_driver user_sp_input_driver = {
225 .probe = user_sp_input_probe,
226 .remove = __devexit_p(user_sp_input_remove),
227 .driver = {
228 .name = USER_SP_INPUT_DRV_NAME,
229 .owner = THIS_MODULE,
230 },
231};
232
233static int __init user_sp_input_init(void)
234{
235 return platform_driver_register(&user_sp_input_driver);
236}
237module_init(user_sp_input_init);
238
239static void __exit user_sp_input_exit(void)
240{
241 platform_driver_unregister(&user_sp_input_driver);
242}
243module_exit(user_sp_input_exit);
244
245MODULE_DESCRIPTION("User SP RC Input driver");
246MODULE_LICENSE("GPL v2");