joydev.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $
  3.  *
  4.  *  Copyright (c) 1999-2000 Vojtech Pavlik 
  5.  *  Copyright (c) 1999 Colin Van Dyke 
  6.  *
  7.  *  Joystick device driver for the input driver suite.
  8.  *
  9.  *  Sponsored by SuSE and Intel
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or 
  15.  * (at your option) any later version.
  16.  * 
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  * 
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25.  * 
  26.  * Should you need to contact me, the author, you can do so either by
  27.  * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  28.  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  29.  */
  30. #include <asm/io.h>
  31. #include <asm/system.h>
  32. #include <asm/segment.h>
  33. #include <linux/delay.h>
  34. #include <linux/errno.h>
  35. #include <linux/joystick.h>
  36. #include <linux/input.h>
  37. #include <linux/kernel.h>
  38. #include <linux/major.h>
  39. #include <linux/slab.h>
  40. #include <linux/mm.h>
  41. #include <linux/miscdevice.h>
  42. #include <linux/module.h>
  43. #include <linux/poll.h>
  44. #include <linux/init.h>
  45. #include <linux/smp_lock.h>
  46. #define JOYDEV_MINOR_BASE 0
  47. #define JOYDEV_MINORS 32
  48. #define JOYDEV_BUFFER_SIZE 64
  49. struct joydev {
  50. int exist;
  51. int open;
  52. int minor;
  53. struct input_handle handle;
  54. wait_queue_head_t wait;
  55. devfs_handle_t devfs;
  56. struct joydev *next;
  57. struct joydev_list *list;
  58. struct js_corr corr[ABS_MAX];
  59. struct JS_DATA_SAVE_TYPE glue;
  60. int nabs;
  61. int nkey;
  62. __u16 keymap[KEY_MAX - BTN_MISC];
  63. __u16 keypam[KEY_MAX - BTN_MISC];
  64. __u8 absmap[ABS_MAX];
  65. __u8 abspam[ABS_MAX];
  66. __s16 abs[ABS_MAX];
  67. };
  68. struct joydev_list {
  69. struct js_event buffer[JOYDEV_BUFFER_SIZE];
  70. int head;
  71. int tail;
  72. int startup;
  73. struct fasync_struct *fasync;
  74. struct joydev *joydev;
  75. struct joydev_list *next;
  76. };
  77. static struct joydev *joydev_table[JOYDEV_MINORS];
  78. MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
  79. MODULE_DESCRIPTION("Joystick device driver");
  80. MODULE_LICENSE("GPL");
  81. MODULE_SUPPORTED_DEVICE("input/js");
  82. static int joydev_correct(int value, struct js_corr *corr)
  83. {
  84. switch (corr->type) {
  85. case JS_CORR_NONE:
  86. break;
  87. case JS_CORR_BROKEN:
  88. value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
  89. ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
  90. ((corr->coef[2] * (value - corr->coef[0])) >> 14);
  91. break;
  92. default:
  93. return 0;
  94. }
  95. if (value < -32767) return -32767;
  96. if (value >  32767) return  32767;
  97. return value;
  98. }
  99. static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
  100. {
  101. struct joydev *joydev = handle->private;
  102. struct joydev_list *list = joydev->list;
  103. struct js_event event;
  104. switch (type) {
  105. case EV_KEY:
  106. if (code < BTN_MISC || value == 2) return;
  107. event.type = JS_EVENT_BUTTON;
  108. event.number = joydev->keymap[code - BTN_MISC];
  109. event.value = value;
  110. break;
  111. case EV_ABS:
  112. event.type = JS_EVENT_AXIS;
  113. event.number = joydev->absmap[code];
  114. event.value = joydev_correct(value, joydev->corr + event.number);
  115. if (event.value == joydev->abs[event.number]) return;
  116. joydev->abs[event.number] = event.value;
  117. break;
  118. default:
  119. return;
  120. }  
  121. event.time = jiffies * (1000 / HZ);
  122. while (list) {
  123. memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
  124. if (list->startup == joydev->nabs + joydev->nkey)
  125. if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
  126. list->startup = 0;
  127. kill_fasync(&list->fasync, SIGIO, POLL_IN);
  128. list = list->next;
  129. }
  130. wake_up_interruptible(&joydev->wait);
  131. }
  132. static int joydev_fasync(int fd, struct file *file, int on)
  133. {
  134. int retval;
  135. struct joydev_list *list = file->private_data;
  136. retval = fasync_helper(fd, file, on, &list->fasync);
  137. return retval < 0 ? retval : 0;
  138. }
  139. static int joydev_release(struct inode * inode, struct file * file)
  140. {
  141. struct joydev_list *list = file->private_data;
  142. struct joydev_list **listptr;
  143. lock_kernel();
  144. listptr = &list->joydev->list;
  145. joydev_fasync(-1, file, 0);
  146. while (*listptr && (*listptr != list))
  147. listptr = &((*listptr)->next);
  148. *listptr = (*listptr)->next;
  149. if (!--list->joydev->open) {
  150. if (list->joydev->exist) {
  151. input_close_device(&list->joydev->handle);
  152. } else {
  153. input_unregister_minor(list->joydev->devfs);
  154. joydev_table[list->joydev->minor] = NULL;
  155. kfree(list->joydev);
  156. }
  157. }
  158. kfree(list);
  159. unlock_kernel();
  160. return 0;
  161. }
  162. static int joydev_open(struct inode *inode, struct file *file)
  163. {
  164. struct joydev_list *list;
  165. int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
  166. if (i >= JOYDEV_MINORS || !joydev_table[i])
  167. return -ENODEV;
  168. if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
  169. return -ENOMEM;
  170. memset(list, 0, sizeof(struct joydev_list));
  171. list->joydev = joydev_table[i];
  172. list->next = joydev_table[i]->list;
  173. joydev_table[i]->list = list;
  174. file->private_data = list;
  175. if (!list->joydev->open++)
  176. if (list->joydev->exist)
  177. input_open_device(&list->joydev->handle);
  178. return 0;
  179. }
  180. static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
  181. {
  182. return -EINVAL;
  183. }
  184. static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
  185. {
  186. DECLARE_WAITQUEUE(wait, current);
  187. struct joydev_list *list = file->private_data;
  188. struct joydev *joydev = list->joydev;
  189. struct input_dev *input = joydev->handle.dev;
  190. int retval = 0;
  191. if (count < sizeof(struct js_event))
  192. return -EINVAL;
  193. if (count == sizeof(struct JS_DATA_TYPE)) {
  194. struct JS_DATA_TYPE data;
  195. int i;
  196. for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
  197. data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
  198. data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
  199. data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
  200. if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
  201. return -EFAULT;
  202. list->startup = 0;
  203. list->tail = list->head;
  204. return sizeof(struct JS_DATA_TYPE);
  205. }
  206. if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
  207. add_wait_queue(&list->joydev->wait, &wait);
  208. current->state = TASK_INTERRUPTIBLE;
  209. while (list->head == list->tail) {
  210. if (file->f_flags & O_NONBLOCK) {
  211. retval = -EAGAIN;
  212. break;
  213. }
  214. if (signal_pending(current)) {
  215. retval = -ERESTARTSYS;
  216. break;
  217. }
  218. schedule();
  219. }
  220. current->state = TASK_RUNNING;
  221. remove_wait_queue(&list->joydev->wait, &wait);
  222. }
  223. if (retval)
  224. return retval;
  225. while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
  226. struct js_event event;
  227. event.time = jiffies * (1000/HZ);
  228. if (list->startup < joydev->nkey) {
  229. event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
  230. event.number = list->startup;
  231. event.value = !!test_bit(joydev->keypam[event.number], input->key);
  232. } else {
  233. event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
  234. event.number = list->startup - joydev->nkey;
  235. event.value = joydev->abs[event.number];
  236. }
  237. if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
  238. return -EFAULT;
  239. list->startup++;
  240. retval += sizeof(struct js_event);
  241. }
  242. while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
  243. if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
  244. return -EFAULT;
  245. list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
  246. retval += sizeof(struct js_event);
  247. }
  248. return retval;
  249. }
  250. /* No kernel lock - fine */
  251. static unsigned int joydev_poll(struct file *file, poll_table *wait)
  252. {
  253. struct joydev_list *list = file->private_data;
  254. poll_wait(file, &list->joydev->wait, wait);
  255. if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
  256. return POLLIN | POLLRDNORM;
  257. return 0;
  258. }
  259. static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  260. {
  261. struct joydev_list *list = file->private_data;
  262. struct joydev *joydev = list->joydev;
  263. struct input_dev *dev = joydev->handle.dev;
  264. int i;
  265. switch (cmd) {
  266. case JS_SET_CAL:
  267. return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
  268. sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
  269. case JS_GET_CAL:
  270. return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR,
  271. sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
  272. case JS_SET_TIMEOUT:
  273. return get_user(joydev->glue.JS_TIMEOUT, (int *) arg);
  274. case JS_GET_TIMEOUT:
  275. return put_user(joydev->glue.JS_TIMEOUT, (int *) arg);
  276. case JS_SET_TIMELIMIT:
  277. return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
  278. case JS_GET_TIMELIMIT:
  279. return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
  280. case JS_SET_ALL:
  281. return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg,
  282. sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
  283. case JS_GET_ALL:
  284. return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue,
  285. sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
  286. case JSIOCGVERSION:
  287. return put_user(JS_VERSION, (__u32 *) arg);
  288. case JSIOCGAXES:
  289. return put_user(joydev->nabs, (__u8 *) arg);
  290. case JSIOCGBUTTONS:
  291. return put_user(joydev->nkey, (__u8 *) arg);
  292. case JSIOCSCORR:
  293. return copy_from_user(joydev->corr, (struct js_corr *) arg,
  294. sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
  295. case JSIOCGCORR:
  296. return copy_to_user((struct js_corr *) arg, joydev->corr,
  297. sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
  298. case JSIOCSAXMAP:
  299. if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
  300. return -EFAULT;
  301. for (i = 0; i < ABS_MAX; i++) {
  302. if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
  303. joydev->absmap[joydev->abspam[i]] = i;
  304. }
  305. return 0;
  306. case JSIOCGAXMAP:
  307. return copy_to_user((__u8 *) arg, joydev->abspam,
  308. sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
  309. case JSIOCSBTNMAP:
  310. if (copy_from_user(joydev->absmap, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
  311. return -EFAULT;
  312. for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
  313. if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
  314. joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
  315. }
  316. return 0;
  317. case JSIOCGBTNMAP:
  318. return copy_to_user((__u16 *) arg, joydev->keypam,
  319. sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
  320. default:
  321. if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
  322. int len;
  323. if (!dev->name) return 0;
  324. len = strlen(dev->name) + 1;
  325. if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
  326. if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT;
  327. return len;
  328. }
  329. }
  330. return -EINVAL;
  331. }
  332. static struct file_operations joydev_fops = {
  333. owner: THIS_MODULE,
  334. read: joydev_read,
  335. write: joydev_write,
  336. poll: joydev_poll,
  337. open: joydev_open,
  338. release: joydev_release,
  339. ioctl: joydev_ioctl,
  340. fasync: joydev_fasync,
  341. };
  342. static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
  343. {
  344. struct joydev *joydev;
  345. int i, j, t, minor;
  346. if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
  347.      (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) &&
  348.      (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
  349. || test_bit(BTN_1, dev->keybit)))) return NULL; 
  350. for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
  351. if (minor == JOYDEV_MINORS) {
  352. printk(KERN_ERR "joydev: no more free joydev devicesn");
  353. return NULL;
  354. }
  355. if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
  356. return NULL;
  357. memset(joydev, 0, sizeof(struct joydev));
  358. init_waitqueue_head(&joydev->wait);
  359. joydev->minor = minor;
  360. joydev_table[minor] = joydev;
  361. joydev->handle.dev = dev;
  362. joydev->handle.handler = handler;
  363. joydev->handle.private = joydev;
  364. joydev->exist = 1;
  365. for (i = 0; i < ABS_MAX; i++)
  366. if (test_bit(i, dev->absbit)) {
  367. joydev->absmap[i] = joydev->nabs;
  368. joydev->abspam[joydev->nabs] = i;
  369. joydev->nabs++;
  370. }
  371. for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
  372. if (test_bit(i + BTN_MISC, dev->keybit)) {
  373. joydev->keymap[i] = joydev->nkey;
  374. joydev->keypam[joydev->nkey] = i + BTN_MISC;
  375. joydev->nkey++;
  376. }
  377. for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
  378. if (test_bit(i + BTN_MISC, dev->keybit)) {
  379. joydev->keymap[i] = joydev->nkey;
  380. joydev->keypam[joydev->nkey] = i + BTN_MISC;
  381. joydev->nkey++;
  382. }
  383. for (i = 0; i < joydev->nabs; i++) {
  384. j = joydev->abspam[i];
  385. if (dev->absmax[j] == dev->absmin[j]) {
  386. joydev->corr[i].type = JS_CORR_NONE;
  387. continue;
  388. }
  389. joydev->corr[i].type = JS_CORR_BROKEN;
  390. joydev->corr[i].prec = dev->absfuzz[j];
  391. joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
  392. joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
  393. if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
  394. continue;
  395. joydev->corr[i].coef[2] = (1 << 29) / t;
  396. joydev->corr[i].coef[3] = (1 << 29) / t;
  397. joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
  398. }
  399. joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
  400. // printk(KERN_INFO "js%d: Joystick device for input%dn", minor, dev->number);
  401. return &joydev->handle;
  402. }
  403. static void joydev_disconnect(struct input_handle *handle)
  404. {
  405. struct joydev *joydev = handle->private;
  406. joydev->exist = 0;
  407. if (joydev->open) {
  408. input_close_device(handle);
  409. } else {
  410. input_unregister_minor(joydev->devfs);
  411. joydev_table[joydev->minor] = NULL;
  412. kfree(joydev);
  413. }
  414. }
  415. static struct input_handler joydev_handler = {
  416. event: joydev_event,
  417. connect: joydev_connect,
  418. disconnect: joydev_disconnect,
  419. fops: &joydev_fops,
  420. minor: JOYDEV_MINOR_BASE,
  421. };
  422. static int __init joydev_init(void)
  423. {
  424. input_register_handler(&joydev_handler);
  425. return 0;
  426. }
  427. static void __exit joydev_exit(void)
  428. {
  429. input_unregister_handler(&joydev_handler);
  430. }
  431. module_init(joydev_init);
  432. module_exit(joydev_exit);