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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* 
  2.  * Driver for PS/2 mouse on IOMD interface
  3.  */
  4. #include <linux/config.h>
  5. #include <linux/sched.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/tty.h>
  8. #include <linux/tty_flip.h>
  9. #include <linux/mm.h>
  10. #include <linux/slab.h>
  11. #include <linux/ptrace.h>
  12. #include <linux/signal.h>
  13. #include <linux/timer.h>
  14. #include <linux/random.h>
  15. #include <linux/ctype.h>
  16. #include <linux/kbd_ll.h>
  17. #include <linux/delay.h>
  18. #include <linux/init.h>
  19. #include <linux/poll.h>
  20. #include <linux/miscdevice.h>
  21. #include <asm/bitops.h>
  22. #include <asm/irq.h>
  23. #include <asm/hardware.h>
  24. #include <asm/io.h>
  25. #include <asm/hardware/iomd.h>
  26. #include <asm/system.h>
  27. #include <asm/uaccess.h>
  28. /*
  29.  * PS/2 Auxiliary Device
  30.  */
  31. static struct aux_queue *queue; /* Mouse data buffer. */
  32. static int aux_count = 0;
  33. /* used when we send commands to the mouse that expect an ACK. */
  34. static unsigned char mouse_reply_expected = 0;
  35. #define MAX_RETRIES 60 /* some aux operations take long time*/
  36. /*
  37.  * Mouse Commands
  38.  */
  39. #define AUX_SET_RES 0xE8 /* Set resolution */
  40. #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
  41. #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
  42. #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
  43. #define AUX_SET_STREAM 0xEA /* Set stream mode */
  44. #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
  45. #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
  46. #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
  47. #define AUX_RESET 0xFF /* Reset aux device */
  48. #define AUX_ACK 0xFA /* Command byte ACK. */
  49. #define AUX_BUF_SIZE 2048 /* This might be better divisible by
  50.    three to make overruns stay in sync
  51.    but then the read function would 
  52.    need a lock etc - ick */
  53. struct aux_queue {
  54. unsigned long head;
  55. unsigned long tail;
  56. wait_queue_head_t proc_list;
  57. struct fasync_struct *fasync;
  58. unsigned char buf[AUX_BUF_SIZE];
  59. };
  60. /*
  61.  * Send a byte to the mouse.
  62.  */
  63. static void aux_write_dev(int val)
  64. {
  65. while (!(iomd_readb(IOMD_MSECTL) & 0x80));
  66. iomd_writeb(val, IOMD_MSEDAT);
  67. }
  68. /*
  69.  * Send a byte to the mouse & handle returned ack
  70.  */
  71. static void aux_write_ack(int val)
  72. {
  73. while (!(iomd_readb(IOMD_MSECTL) & 0x80));
  74. iomd_writeb(val, IOMD_MSEDAT);
  75. /* we expect an ACK in response. */
  76. mouse_reply_expected++;
  77. }
  78. static unsigned char get_from_queue(void)
  79. {
  80. unsigned char result;
  81. result = queue->buf[queue->tail];
  82. queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
  83. return result;
  84. }
  85. static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  86. {
  87. int val = iomd_readb(IOMD_MSEDAT);
  88. if (mouse_reply_expected) {
  89. if (val == AUX_ACK) {
  90. mouse_reply_expected--;
  91. return;
  92. }
  93. mouse_reply_expected = 0;
  94. }
  95. add_mouse_randomness(val);
  96. if (aux_count) {
  97. int head = queue->head;
  98. queue->buf[head] = val;
  99. head = (head + 1) & (AUX_BUF_SIZE-1);
  100. if (head != queue->tail) {
  101. queue->head = head;
  102. kill_fasync(&queue->fasync, SIGIO, POLL_IN);
  103. wake_up_interruptible(&queue->proc_list);
  104. }
  105. }
  106. }
  107. static inline int queue_empty(void)
  108. {
  109. return queue->head == queue->tail;
  110. }
  111. static int fasync_aux(int fd, struct file *filp, int on)
  112. {
  113. int retval;
  114. retval = fasync_helper(fd, filp, on, &queue->fasync);
  115. if (retval < 0)
  116. return retval;
  117. return 0;
  118. }
  119. /*
  120.  * Random magic cookie for the aux device
  121.  */
  122. #define AUX_DEV ((void *)queue)
  123. static int release_aux(struct inode * inode, struct file * file)
  124. {
  125. fasync_aux(-1, file, 0);
  126. if (--aux_count)
  127. return 0;
  128. free_irq(IRQ_MOUSERX, AUX_DEV);
  129. return 0;
  130. }
  131. /*
  132.  * Install interrupt handler.
  133.  * Enable auxiliary device.
  134.  */
  135. static int open_aux(struct inode * inode, struct file * file)
  136. {
  137. if (aux_count++)
  138. return 0;
  139. queue->head = queue->tail = 0; /* Flush input queue */
  140. if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse", 
  141. AUX_DEV)) {
  142. aux_count--;
  143. return -EBUSY;
  144. }
  145. aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
  146. return 0;
  147. }
  148. /*
  149.  * Put bytes from input queue to buffer.
  150.  */
  151. static ssize_t read_aux(struct file * file, char * buffer,
  152. size_t count, loff_t *ppos)
  153. {
  154. DECLARE_WAITQUEUE(wait, current);
  155. ssize_t i = count;
  156. unsigned char c;
  157. if (queue_empty()) {
  158. if (file->f_flags & O_NONBLOCK)
  159. return -EAGAIN;
  160. add_wait_queue(&queue->proc_list, &wait);
  161. repeat:
  162. current->state = TASK_INTERRUPTIBLE;
  163. if (queue_empty() && !signal_pending(current)) {
  164. schedule();
  165. goto repeat;
  166. }
  167. current->state = TASK_RUNNING;
  168. remove_wait_queue(&queue->proc_list, &wait);
  169. }
  170. while (i > 0 && !queue_empty()) {
  171. c = get_from_queue();
  172. put_user(c, buffer++);
  173. i--;
  174. }
  175. if (count-i) {
  176. file->f_dentry->d_inode->i_atime = CURRENT_TIME;
  177. return count-i;
  178. }
  179. if (signal_pending(current))
  180. return -ERESTARTSYS;
  181. return 0;
  182. }
  183. /*
  184.  * Write to the aux device.
  185.  */
  186. static ssize_t write_aux(struct file * file, const char * buffer,
  187.  size_t count, loff_t *ppos)
  188. {
  189. ssize_t retval = 0;
  190. if (count) {
  191. ssize_t written = 0;
  192. if (count > 32)
  193. count = 32; /* Limit to 32 bytes. */
  194. do {
  195. char c;
  196. get_user(c, buffer++);
  197. aux_write_dev(c);
  198. written++;
  199. } while (--count);
  200. retval = -EIO;
  201. if (written) {
  202. retval = written;
  203. file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
  204. }
  205. }
  206. return retval;
  207. }
  208. static unsigned int aux_poll(struct file *file, poll_table * wait)
  209. {
  210. poll_wait(file, &queue->proc_list, wait);
  211. if (!queue_empty())
  212. return POLLIN | POLLRDNORM;
  213. return 0;
  214. }
  215. struct file_operations psaux_fops = {
  216. read: read_aux,
  217. write: write_aux,
  218. poll: aux_poll,
  219. open: open_aux,
  220. release: release_aux,
  221. fasync: fasync_aux,
  222. };
  223. /*
  224.  * Initialize driver.
  225.  */
  226. static struct miscdevice psaux_mouse = {
  227. PSMOUSE_MINOR, "psaux", &psaux_fops
  228. };
  229. int __init psaux_init(void)
  230. {
  231. /* Reset the mouse state machine. */
  232. iomd_writeb(0, IOMD_MSECTL);
  233. iomd_writeb(8, IOMD_MSECTL);
  234.   
  235. queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
  236. if (queue == NULL)
  237. return -ENOMEM;
  238. if (misc_register(&psaux_mouse)) {
  239. kfree(queue);
  240. return -ENODEV;
  241. }
  242. memset(queue, 0, sizeof(*queue));
  243. queue->head = queue->tail = 0;
  244. init_waitqueue_head(&queue->proc_list);
  245. aux_write_ack(AUX_SET_SAMPLE);
  246. aux_write_ack(100); /* 100 samples/sec */
  247. aux_write_ack(AUX_SET_RES);
  248. aux_write_ack(3); /* 8 counts per mm */
  249. aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
  250. return 0;
  251. }