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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/drivers/char/busmouse.c
  3.  *
  4.  * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk>
  5.  *  Protocol taken from original busmouse.c
  6.  *  read() waiting taken from psaux.c
  7.  *
  8.  * Medium-level interface for quadrature or bus mice.
  9.  */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/signal.h>
  14. #include <linux/slab.h>
  15. #include <linux/errno.h>
  16. #include <linux/mm.h>
  17. #include <linux/poll.h>
  18. #include <linux/miscdevice.h>
  19. #include <linux/random.h>
  20. #include <linux/init.h>
  21. #include <linux/smp_lock.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/system.h>
  24. #include <asm/io.h>
  25. #include "busmouse.h"
  26. /* Uncomment this if your mouse drivers expect the kernel to
  27.  * return with EAGAIN if the mouse does not have any events
  28.  * available, even if the mouse is opened in blocking mode.
  29.  * Please report use of this "feature" to the author using the
  30.  * above address.
  31.  */
  32. /*#define BROKEN_MOUSE*/
  33. struct busmouse_data {
  34. struct miscdevice miscdev;
  35. struct busmouse *ops;
  36. spinlock_t lock;
  37. wait_queue_head_t wait;
  38. struct fasync_struct *fasyncptr;
  39. char active;
  40. char buttons;
  41. char ready;
  42. int dxpos;
  43. int dypos;
  44. };
  45. #define NR_MICE 15
  46. #define FIRST_MOUSE 0
  47. #define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
  48. #define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
  49. /*
  50.  * List of mice and guarding semaphore. You must take the semaphore
  51.  * before you take the misc device semaphore if you need both
  52.  */
  53.  
  54. static struct busmouse_data *busmouse_data[NR_MICE];
  55. static DECLARE_MUTEX(mouse_sem);
  56. /**
  57.  * busmouse_add_movement - notification of a change of mouse position
  58.  * @mousedev: mouse number
  59.  * @dx: delta X movement
  60.  * @dy: delta Y movement
  61.  * @buttons: new button state
  62.  *
  63.  * Updates the mouse position and button information. The mousedev
  64.  * parameter is the value returned from register_busmouse. The
  65.  * movement information is updated, and the new button state is
  66.  * saved.  A waiting user thread is woken.
  67.  */
  68.  
  69. void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
  70. {
  71. struct busmouse_data *mse = busmouse_data[mousedev];
  72. int changed;
  73. spin_lock(&mse->lock);
  74. changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
  75. if (changed) {
  76. add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
  77. mse->buttons = buttons;
  78. mse->dxpos += dx;
  79. mse->dypos += dy;
  80. mse->ready = 1;
  81. /*
  82.  * keep dx/dy reasonable, but still able to track when X (or
  83.  * whatever) must page or is busy (i.e. long waits between
  84.  * reads)
  85.  */
  86. if (mse->dxpos < -2048)
  87. mse->dxpos = -2048;
  88. if (mse->dxpos > 2048)
  89. mse->dxpos = 2048;
  90. if (mse->dypos < -2048)
  91. mse->dypos = -2048;
  92. if (mse->dypos > 2048)
  93. mse->dypos = 2048;
  94. }
  95. spin_unlock(&mse->lock);
  96. if (changed) {
  97. wake_up(&mse->wait);
  98. kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);
  99. }
  100. }
  101. /**
  102.  * busmouse_add_movement - notification of a change of mouse position
  103.  * @mousedev: mouse number
  104.  * @dx: delta X movement
  105.  * @dy: delta Y movement
  106.  *
  107.  * Updates the mouse position. The mousedev parameter is the value
  108.  * returned from register_busmouse. The movement information is
  109.  * updated, and a waiting user thread is woken.
  110.  */
  111.  
  112. void busmouse_add_movement(int mousedev, int dx, int dy)
  113. {
  114. struct busmouse_data *mse = busmouse_data[mousedev];
  115. busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
  116. }
  117. /**
  118.  * busmouse_add_buttons - notification of a change of button state
  119.  * @mousedev: mouse number
  120.  * @clear: mask of buttons to clear
  121.  * @eor: mask of buttons to change
  122.  *
  123.  * Updates the button state. The mousedev parameter is the value
  124.  * returned from register_busmouse. The buttons are updated by:
  125.  * new_state = (old_state & ~clear) ^ eor
  126.  * A waiting user thread is woken up.
  127.  */
  128.  
  129. void busmouse_add_buttons(int mousedev, int clear, int eor)
  130. {
  131. struct busmouse_data *mse = busmouse_data[mousedev];
  132. busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
  133. }
  134. static int busmouse_fasync(int fd, struct file *filp, int on)
  135. {
  136. struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
  137. int retval;
  138. retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
  139. if (retval < 0)
  140. return retval;
  141. return 0;
  142. }
  143. static int busmouse_release(struct inode *inode, struct file *file)
  144. {
  145. struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
  146. int ret = 0;
  147. lock_kernel();
  148. busmouse_fasync(-1, file, 0);
  149. if (--mse->active == 0) {
  150. if (mse->ops->release)
  151. ret = mse->ops->release(inode, file);
  152.     if (mse->ops->owner)
  153. __MOD_DEC_USE_COUNT(mse->ops->owner);
  154. mse->ready = 0;
  155. }
  156. unlock_kernel();
  157. return ret;
  158. }
  159. static int busmouse_open(struct inode *inode, struct file *file)
  160. {
  161. struct busmouse_data *mse;
  162. unsigned int mousedev;
  163. int ret;
  164. mousedev = DEV_TO_MOUSE(inode->i_rdev);
  165. if (mousedev >= NR_MICE)
  166. return -EINVAL;
  167. down(&mouse_sem);
  168. mse = busmouse_data[mousedev];
  169. ret = -ENODEV;
  170. if (!mse || !mse->ops) /* shouldn't happen, but... */
  171. goto end;
  172. if (mse->ops->owner && !try_inc_mod_count(mse->ops->owner))
  173. goto end;
  174. ret = 0;
  175. if (mse->ops->open) {
  176. ret = mse->ops->open(inode, file);
  177. if (ret && mse->ops->owner)
  178. __MOD_DEC_USE_COUNT(mse->ops->owner);
  179. }
  180. if (ret)
  181. goto end;
  182. file->private_data = mse;
  183. if (mse->active++)
  184. goto end;
  185. spin_lock_irq(&mse->lock);
  186. mse->ready   = 0;
  187. mse->dxpos   = 0;
  188. mse->dypos   = 0;
  189. mse->buttons = mse->ops->init_button_state;
  190. spin_unlock_irq(&mse->lock);
  191. end:
  192. up(&mouse_sem);
  193. return ret;
  194. }
  195. static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
  196. {
  197. return -EINVAL;
  198. }
  199. static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
  200. {
  201. struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
  202. DECLARE_WAITQUEUE(wait, current);
  203. int dxpos, dypos, buttons;
  204. if (count < 3)
  205. return -EINVAL;
  206. spin_lock_irq(&mse->lock);
  207. if (!mse->ready) {
  208. #ifdef BROKEN_MOUSE
  209. spin_unlock_irq(&mse->lock);
  210. return -EAGAIN;
  211. #else
  212. if (file->f_flags & O_NONBLOCK) {
  213. spin_unlock_irq(&mse->lock);
  214. return -EAGAIN;
  215. }
  216. add_wait_queue(&mse->wait, &wait);
  217. repeat:
  218. set_current_state(TASK_INTERRUPTIBLE);
  219. if (!mse->ready && !signal_pending(current)) {
  220. spin_unlock_irq(&mse->lock);
  221. schedule();
  222. spin_lock_irq(&mse->lock);
  223. goto repeat;
  224. }
  225. current->state = TASK_RUNNING;
  226. remove_wait_queue(&mse->wait, &wait);
  227. if (signal_pending(current)) {
  228. spin_unlock_irq(&mse->lock);
  229. return -ERESTARTSYS;
  230. }
  231. #endif
  232. }
  233. dxpos = mse->dxpos;
  234. dypos = mse->dypos;
  235. buttons = mse->buttons;
  236. if (dxpos < -127)
  237. dxpos =- 127;
  238. if (dxpos > 127)
  239. dxpos = 127;
  240. if (dypos < -127)
  241. dypos =- 127;
  242. if (dypos > 127)
  243. dypos = 127;
  244. mse->dxpos -= dxpos;
  245. mse->dypos -= dypos;
  246. /* This is something that many drivers have apparantly
  247.  * forgotten...  If the X and Y positions still contain
  248.  * information, we still have some info ready for the
  249.  * user program...
  250.  */
  251. mse->ready = mse->dxpos || mse->dypos;
  252. spin_unlock_irq(&mse->lock);
  253. /* Write out data to the user.  Format is:
  254.  *   byte 0 - identifer (0x80) and (inverted) mouse buttons
  255.  *   byte 1 - X delta position +/- 127
  256.  *   byte 2 - Y delta position +/- 127
  257.  */
  258. if (put_user((char)buttons | 128, buffer) ||
  259.     put_user((char)dxpos, buffer + 1) ||
  260.     put_user((char)dypos, buffer + 2))
  261. return -EFAULT;
  262. if (count > 3 && clear_user(buffer + 3, count - 3))
  263. return -EFAULT;
  264. file->f_dentry->d_inode->i_atime = CURRENT_TIME;
  265. return count;
  266. }
  267. /* No kernel lock held - fine */
  268. static unsigned int busmouse_poll(struct file *file, poll_table *wait)
  269. {
  270. struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
  271. poll_wait(file, &mse->wait, wait);
  272. if (mse->ready)
  273. return POLLIN | POLLRDNORM;
  274. return 0;
  275. }
  276. struct file_operations busmouse_fops=
  277. {
  278. owner: THIS_MODULE,
  279. read: busmouse_read,
  280. write: busmouse_write,
  281. poll: busmouse_poll,
  282. open: busmouse_open,
  283. release: busmouse_release,
  284. fasync: busmouse_fasync,
  285. };
  286. /**
  287.  * register_busmouse - register a bus mouse interface
  288.  * @ops: busmouse structure for the mouse
  289.  *
  290.  * Registers a mouse with the driver. The return is mouse number on
  291.  * success and a negative errno code on an error. The passed ops
  292.  * structure most not be freed until the mouser is unregistered
  293.  */
  294.  
  295. int register_busmouse(struct busmouse *ops)
  296. {
  297. unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
  298. struct busmouse_data *mse;
  299. int ret;
  300. if (msedev >= NR_MICE) {
  301. printk(KERN_ERR "busmouse: trying to allocate mouse on minor %dn",
  302.        ops->minor);
  303. return -EINVAL;
  304. }
  305. mse = kmalloc(sizeof(*mse), GFP_KERNEL);
  306. if (!mse)
  307. return -ENOMEM;
  308. down(&mouse_sem);
  309. if (busmouse_data[msedev])
  310. {
  311. up(&mouse_sem);
  312. kfree(mse);
  313. return -EBUSY;
  314. }
  315. memset(mse, 0, sizeof(*mse));
  316. mse->miscdev.minor = ops->minor;
  317. mse->miscdev.name = ops->name;
  318. mse->miscdev.fops = &busmouse_fops;
  319. mse->ops = ops;
  320. mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
  321. init_waitqueue_head(&mse->wait);
  322. busmouse_data[msedev] = mse;
  323. ret = misc_register(&mse->miscdev);
  324. if (!ret)
  325. ret = msedev;
  326. up(&mouse_sem);
  327. return ret;
  328. }
  329. /**
  330.  * unregister_busmouse - unregister a bus mouse interface
  331.  * @mousedev: Mouse number to release
  332.  *
  333.  * Unregister a previously installed mouse handler. The mousedev
  334.  * passed is the return code from a previous call to register_busmouse
  335.  */
  336.  
  337. int unregister_busmouse(int mousedev)
  338. {
  339. int err = -EINVAL;
  340. if (mousedev < 0)
  341. return 0;
  342. if (mousedev >= NR_MICE) {
  343. printk(KERN_ERR "busmouse: trying to free mouse on"
  344.        " mousedev %dn", mousedev);
  345. return -EINVAL;
  346. }
  347. down(&mouse_sem);
  348. if (!busmouse_data[mousedev]) {
  349. printk(KERN_WARNING "busmouse: trying to free free mouse"
  350.        " on mousedev %dn", mousedev);
  351. goto fail;
  352. }
  353. if (busmouse_data[mousedev]->active) {
  354. printk(KERN_ERR "busmouse: trying to free active mouse"
  355.        " on mousedev %dn", mousedev);
  356. goto fail;
  357. }
  358. err = misc_deregister(&busmouse_data[mousedev]->miscdev);
  359. kfree(busmouse_data[mousedev]);
  360. busmouse_data[mousedev] = NULL;
  361. fail:
  362. up(&mouse_sem);
  363. return err;
  364. }
  365. EXPORT_SYMBOL(busmouse_add_movementbuttons);
  366. EXPORT_SYMBOL(busmouse_add_movement);
  367. EXPORT_SYMBOL(busmouse_add_buttons);
  368. EXPORT_SYMBOL(register_busmouse);
  369. EXPORT_SYMBOL(unregister_busmouse);
  370. MODULE_LICENSE("GPL");