2 * User level driver support for input subsystem
4 * Heavily based on evdev.c by Vojtech Pavlik
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
24 * - first public version
26 #include <linux/poll.h>
27 #include <linux/slab.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/input.h>
31 #include <linux/smp_lock.h>
33 #include <linux/miscdevice.h>
34 #include <linux/uinput.h>
36 static int uinput_dev_open(struct input_dev
*dev
)
41 static void uinput_dev_close(struct input_dev
*dev
)
46 static int uinput_dev_event(struct input_dev
*dev
, unsigned int type
, unsigned int code
, int value
)
48 struct uinput_device
*udev
;
50 udev
= (struct uinput_device
*)dev
->private;
52 udev
->buff
[udev
->head
].type
= type
;
53 udev
->buff
[udev
->head
].code
= code
;
54 udev
->buff
[udev
->head
].value
= value
;
55 do_gettimeofday(&udev
->buff
[udev
->head
].time
);
56 udev
->head
= (udev
->head
+ 1) % UINPUT_BUFFER_SIZE
;
58 wake_up_interruptible(&udev
->waitq
);
63 static int uinput_dev_upload_effect(struct input_dev
*dev
, struct ff_effect
*effect
)
68 static int uinput_dev_erase_effect(struct input_dev
*dev
, int effect_id
)
73 static int uinput_create_device(struct uinput_device
*udev
)
75 if (!udev
->dev
->name
) {
76 printk(KERN_DEBUG
"%s: write device info first\n", UINPUT_NAME
);
80 udev
->dev
->open
= uinput_dev_open
;
81 udev
->dev
->close
= uinput_dev_close
;
82 udev
->dev
->event
= uinput_dev_event
;
83 udev
->dev
->upload_effect
= uinput_dev_upload_effect
;
84 udev
->dev
->erase_effect
= uinput_dev_erase_effect
;
85 udev
->dev
->private = udev
;
87 init_waitqueue_head(&(udev
->waitq
));
89 input_register_device(udev
->dev
);
91 set_bit(UIST_CREATED
, &(udev
->state
));
96 static int uinput_destroy_device(struct uinput_device
*udev
)
98 if (!test_bit(UIST_CREATED
, &(udev
->state
))) {
99 printk(KERN_WARNING
"%s: create the device first\n", UINPUT_NAME
);
103 input_unregister_device(udev
->dev
);
105 clear_bit(UIST_CREATED
, &(udev
->state
));
110 static int uinput_open(struct inode
*inode
, struct file
*file
)
112 struct uinput_device
*newdev
;
113 struct input_dev
*newinput
;
115 newdev
= kmalloc(sizeof(struct uinput_device
), GFP_KERNEL
);
118 memset(newdev
, 0, sizeof(struct uinput_device
));
120 newinput
= kmalloc(sizeof(struct input_dev
), GFP_KERNEL
);
123 memset(newinput
, 0, sizeof(struct input_dev
));
125 newdev
->dev
= newinput
;
127 file
->private_data
= newdev
;
136 static int uinput_validate_absbits(struct input_dev
*dev
)
141 for (cnt
= 0; cnt
< ABS_MAX
; cnt
++) {
142 if (!test_bit(cnt
, dev
->absbit
))
145 if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
146 (dev
->absmax
[cnt
] <= dev
->absmin
[cnt
])) {
148 "%s: invalid abs[%02x] min:%d max:%d\n",
150 dev
->absmin
[cnt
], dev
->absmax
[cnt
]);
155 if ((dev
->absflat
[cnt
] < dev
->absmin
[cnt
]) ||
156 (dev
->absflat
[cnt
] > dev
->absmax
[cnt
])) {
158 "%s: absflat[%02x] out of range: %d "
160 UINPUT_NAME
, cnt
, dev
->absflat
[cnt
],
161 dev
->absmin
[cnt
], dev
->absmax
[cnt
]);
169 static int uinput_alloc_device(struct file
*file
, const char *buffer
, size_t count
)
171 struct uinput_user_dev
*user_dev
;
172 struct input_dev
*dev
;
173 struct uinput_device
*udev
;
179 udev
= (struct uinput_device
*)file
->private_data
;
182 user_dev
= kmalloc(sizeof(*user_dev
), GFP_KERNEL
);
188 if (copy_from_user(user_dev
, buffer
, sizeof(struct uinput_user_dev
))) {
193 if (NULL
!= dev
->name
)
196 size
= strnlen(user_dev
->name
, UINPUT_MAX_NAME_SIZE
) + 1;
197 dev
->name
= kmalloc(size
, GFP_KERNEL
);
203 strlcpy(dev
->name
, user_dev
->name
, size
);
204 dev
->id
.bustype
= user_dev
->id
.bustype
;
205 dev
->id
.vendor
= user_dev
->id
.vendor
;
206 dev
->id
.product
= user_dev
->id
.product
;
207 dev
->id
.version
= user_dev
->id
.version
;
208 dev
->ff_effects_max
= user_dev
->ff_effects_max
;
210 size
= sizeof(int) * (ABS_MAX
+ 1);
211 memcpy(dev
->absmax
, user_dev
->absmax
, size
);
212 memcpy(dev
->absmin
, user_dev
->absmin
, size
);
213 memcpy(dev
->absfuzz
, user_dev
->absfuzz
, size
);
214 memcpy(dev
->absflat
, user_dev
->absflat
, size
);
216 /* check if absmin/absmax/absfuzz/absflat are filled as
217 * told in Documentation/input/input-programming.txt */
218 if (test_bit(EV_ABS
, dev
->evbit
)) {
219 retval
= uinput_validate_absbits(dev
);
229 static int uinput_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*ppos
)
231 struct uinput_device
*udev
= file
->private_data
;
233 if (test_bit(UIST_CREATED
, &(udev
->state
))) {
234 struct input_event ev
;
236 if (copy_from_user(&ev
, buffer
, sizeof(struct input_event
)))
238 input_event(udev
->dev
, ev
.type
, ev
.code
, ev
.value
);
241 count
= uinput_alloc_device(file
, buffer
, count
);
246 static ssize_t
uinput_read(struct file
*file
, char *buffer
, size_t count
, loff_t
*ppos
)
248 struct uinput_device
*udev
= file
->private_data
;
251 if (!test_bit(UIST_CREATED
, &(udev
->state
)))
254 if ((udev
->head
== udev
->tail
) && (file
->f_flags
& O_NONBLOCK
))
257 retval
= wait_event_interruptible(udev
->waitq
,
258 (udev
->head
!= udev
->tail
) ||
259 !test_bit(UIST_CREATED
, &(udev
->state
)));
264 if (!test_bit(UIST_CREATED
, &(udev
->state
)))
267 while ((udev
->head
!= udev
->tail
) &&
268 (retval
+ sizeof(struct input_event
) <= count
)) {
269 if (copy_to_user(buffer
+ retval
, &(udev
->buff
[udev
->tail
]),
270 sizeof(struct input_event
))) return -EFAULT
;
271 udev
->tail
= (udev
->tail
+ 1) % UINPUT_BUFFER_SIZE
;
272 retval
+= sizeof(struct input_event
);
278 static unsigned int uinput_poll(struct file
*file
, poll_table
*wait
)
280 struct uinput_device
*udev
= file
->private_data
;
282 poll_wait(file
, &udev
->waitq
, wait
);
284 if (udev
->head
!= udev
->tail
)
285 return POLLIN
| POLLRDNORM
;
290 static int uinput_burn_device(struct uinput_device
*udev
)
292 if (test_bit(UIST_CREATED
, &(udev
->state
)))
293 uinput_destroy_device(udev
);
301 static int uinput_close(struct inode
*inode
, struct file
*file
)
303 return uinput_burn_device((struct uinput_device
*)file
->private_data
);
306 static int uinput_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
309 struct uinput_device
*udev
;
311 udev
= (struct uinput_device
*)file
->private_data
;
313 /* device attributes can not be changed after the device is created */
314 if (cmd
>= UI_SET_EVBIT
&& test_bit(UIST_CREATED
, &(udev
->state
)))
319 retval
= uinput_create_device(udev
);
323 retval
= uinput_destroy_device(udev
);
328 set_bit(arg
, udev
->dev
->evbit
);
332 set_bit(arg
, udev
->dev
->keybit
);
336 set_bit(arg
, udev
->dev
->relbit
);
340 set_bit(arg
, udev
->dev
->absbit
);
344 set_bit(arg
, udev
->dev
->mscbit
);
348 set_bit(arg
, udev
->dev
->ledbit
);
352 set_bit(arg
, udev
->dev
->sndbit
);
356 set_bit(arg
, udev
->dev
->ffbit
);
365 struct file_operations uinput_fops
= {
366 .owner
= THIS_MODULE
,
368 .release
= uinput_close
,
370 .write
= uinput_write
,
372 .ioctl
= uinput_ioctl
,
375 static struct miscdevice uinput_misc
= {
376 .fops
= &uinput_fops
,
377 .minor
= UINPUT_MINOR
,
381 static int __init
uinput_init(void)
383 return misc_register(&uinput_misc
);
386 static void __exit
uinput_exit(void)
388 misc_deregister(&uinput_misc
);
391 MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
392 MODULE_DESCRIPTION("User level driver support for input subsystem");
393 MODULE_LICENSE("GPL");
395 module_init(uinput_init
);
396 module_exit(uinput_exit
);