mouse_ps2.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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