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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *      LASI PS/2 keyboard/psaux driver for HP-PARISC workstations
  3.  *      
  4.  *      (c) Copyright 1999 The Puffin Group Inc.
  5.  *      by Alex deVries <adevries@thepuffingroup.com>
  6.  * Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org>
  7.  *
  8.  * 2000/10/26 Debacker Xavier (debackex@esiee.fr)
  9.  * implemented the psaux and controlled the mouse scancode based on pc_keyb.c
  10.  * Marteau Thomas (marteaut@esiee.fr)
  11.  * fixed leds control
  12.  *
  13.  * 2001/12/17 Marteau Thomas (marteaut@esiee.fr)
  14.  * get nice initialisation procedure
  15.  */
  16. #include <linux/config.h>
  17. #include <linux/types.h>
  18. #include <linux/ptrace.h> /* interrupt.h wants struct pt_regs defined */
  19. #include <linux/interrupt.h>
  20. #include <linux/sched.h> /* for request_irq/free_irq */
  21. #include <linux/ioport.h>
  22. #include <linux/kernel.h>
  23. #include <linux/wait.h>
  24. #include <linux/delay.h>
  25. #include <linux/errno.h>
  26. #include <linux/init.h>
  27. #include <linux/module.h>
  28. #include <linux/pc_keyb.h>
  29. #include <linux/kbd_kern.h>
  30. /* mouse includes */
  31. #include <linux/miscdevice.h>
  32. #include <linux/slab.h>
  33. #include <linux/random.h>
  34. #include <linux/spinlock.h>
  35. #include <linux/smp_lock.h>
  36. #include <linux/poll.h>
  37. #include <asm/hardware.h>
  38. #include <asm/keyboard.h>
  39. #include <asm/gsc.h>
  40. #include <asm/uaccess.h>
  41. /* HP specific LASI PS/2 keyboard and psaux constants */
  42. #define AUX_REPLY_ACK 0xFA /* Command byte ACK. */
  43. #define AUX_RESEND 0xFE /* Sent by the keyb. Asking for resending the last command. */
  44. #define AUX_RECONNECT 0xAA /* scancode when ps2 device is plugged (back) in */
  45. #define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */
  46. #define LASI_ID 0x00 /* ID and reset port offsets */
  47. #define LASI_RESET 0x00
  48. #define LASI_RCVDATA 0x04 /* receive and transmit port offsets */
  49. #define LASI_XMTDATA 0x04
  50. #define LASI_CONTROL 0x08 /* see: control register bits */
  51. #define LASI_STATUS 0x0C /* see: status register bits */
  52. /* control register bits */
  53. #define LASI_CTRL_ENBL 0x01 /* enable interface */
  54. #define LASI_CTRL_LPBXR 0x02 /* loopback operation */
  55. #define LASI_CTRL_DIAG 0x20 /* directly control clock/data line */
  56. #define LASI_CTRL_DATDIR 0x40 /* data line direct control */
  57. #define LASI_CTRL_CLKDIR 0x80 /* clock line direct control */
  58. /* status register bits */
  59. #define LASI_STAT_RBNE 0x01
  60. #define LASI_STAT_TBNE 0x02
  61. #define LASI_STAT_TERR 0x04
  62. #define LASI_STAT_PERR 0x08
  63. #define LASI_STAT_CMPINTR 0x10
  64. #define LASI_STAT_DATSHD 0x40
  65. #define LASI_STAT_CLKSHD 0x80
  66. static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
  67. static unsigned long lasikbd_hpa;
  68. static volatile int cmd_status;
  69. static inline u8 read_input(unsigned long hpa)
  70. {
  71. return gsc_readb(hpa+LASI_RCVDATA);
  72. }
  73. static inline u8 read_control(unsigned long hpa)
  74. {
  75.         return gsc_readb(hpa+LASI_CONTROL);
  76. }
  77. static inline void write_control(u8 val, unsigned long hpa)
  78. {
  79. gsc_writeb(val, hpa+LASI_CONTROL);
  80. }
  81. static inline u8 read_status(unsigned long hpa)
  82. {
  83.         return gsc_readb(hpa+LASI_STATUS);
  84. }
  85. /* XXX should this grab the spinlock? */
  86. static int write_output(u8 val, unsigned long hpa)
  87. {
  88. int wait = 250;
  89. while (read_status(hpa) & LASI_STAT_TBNE) {
  90. if (!--wait) {
  91. return 0;
  92. }
  93. mdelay(1);
  94. }
  95. gsc_writeb(val, hpa+LASI_XMTDATA);
  96. return 1;
  97. }
  98. /* XXX should this grab the spinlock? */
  99. static u8 wait_input(unsigned long hpa)
  100. {
  101. int wait = 250;
  102. while (!(read_status(hpa) & LASI_STAT_RBNE)) {
  103. if (!--wait) {
  104. return 0;
  105. }
  106. mdelay(1);
  107. }
  108. return read_input(hpa);      
  109. }
  110. /* This function is the PA-RISC adaptation of i386 source */
  111. static inline int aux_write_ack(u8 val)
  112. {
  113.       return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);
  114. }
  115. /* This is wrong, should do something like the pc driver, which sends
  116.  * the command up to 3 times at 1 second intervals, checking once
  117.  * per millisecond for an acknowledge.
  118.  */
  119. static void lasikbd_leds(unsigned char leds)
  120. {
  121. int loop = 1000;
  122. if (!lasikbd_hpa)
  123. return;
  124. cmd_status=2;
  125. while (cmd_status!=0 && --loop > 0) {
  126. write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
  127. mdelay(5); 
  128. }
  129.    
  130. cmd_status=2;
  131. while (cmd_status!=0 && --loop > 0) {
  132. write_output(leds, lasikbd_hpa);
  133. mdelay(5);
  134. }
  135. cmd_status=2;
  136. while (cmd_status!=0 && --loop > 0) {
  137.    write_output(KBD_CMD_ENABLE, lasikbd_hpa);   
  138.    mdelay(5);
  139. }
  140. if (loop <= 0)
  141. printk("lasikbd_leds: timeoutn");
  142. }
  143. #if 0
  144. /* this might become useful again at some point.  not now  -prumpf */
  145. int lasi_ps2_test(void *hpa)
  146. {
  147. u8 control,c;
  148. int i, ret = 0;
  149. control = read_control(hpa);
  150. write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa);
  151. for (i=0; i<256; i++) {
  152. write_output(i, hpa);
  153. while (!(read_status(hpa) & LASI_STAT_RBNE))
  154.     /* just wait */;
  155.     
  156. c = read_input(hpa);
  157. if (c != i)
  158. ret--;
  159. }
  160. write_control(control, hpa);
  161. return ret;
  162. }
  163. #endif 
  164. static int init_keyb(unsigned long hpa)
  165. {
  166. int res = 0;
  167. unsigned long flags;
  168. spin_lock_irqsave(&kbd_controller_lock, flags);
  169. if (write_output(KBD_CMD_SET_LEDS, hpa) &&
  170. wait_input(hpa) == AUX_REPLY_ACK &&
  171. write_output(0, hpa) &&
  172. wait_input(hpa) == AUX_REPLY_ACK &&
  173. write_output(KBD_CMD_ENABLE, hpa) &&
  174. wait_input(hpa) == AUX_REPLY_ACK)
  175. res = 1;
  176. spin_unlock_irqrestore(&kbd_controller_lock, flags);
  177. return res;
  178. }
  179. static void __init lasi_ps2_reset(unsigned long hpa)
  180. {
  181. u8 control;
  182. /* reset the interface */
  183. gsc_writeb(0xff, hpa+LASI_RESET);
  184. gsc_writeb(0x0 , hpa+LASI_RESET);
  185. /* enable it */
  186. control = read_control(hpa);
  187. write_control(control | LASI_CTRL_ENBL, hpa);
  188. }
  189. /* Greatly inspired by pc_keyb.c */
  190. /*
  191.  * Wait for keyboard controller input buffer to drain.
  192.  *
  193.  * Don't use 'jiffies' so that we don't depend on
  194.  * interrupts..
  195.  *
  196.  * Quote from PS/2 System Reference Manual:
  197.  *
  198.  * "Address hex 0060 and address hex 0064 should be written only when
  199.  * the input-buffer-full bit and output-buffer-full bit in the
  200.  * Controller Status register are set 0."
  201.  */
  202. #ifdef CONFIG_PSMOUSE
  203. static struct aux_queue *queue;
  204. static unsigned char mouse_reply_expected;
  205. static int  aux_count;
  206. static int fasync_aux(int fd, struct file *filp, int on)
  207. {
  208. int retval;
  209. retval = fasync_helper(fd, filp, on, &queue->fasync);
  210. if (retval < 0)
  211. return retval;
  212. return 0;
  213. }
  214. static inline void handle_mouse_scancode(unsigned char scancode)
  215. {
  216. if (mouse_reply_expected) {
  217. if (scancode == AUX_REPLY_ACK) {
  218. mouse_reply_expected--;
  219. return;
  220. }
  221. mouse_reply_expected = 0;
  222. }
  223. else if (scancode == AUX_RECONNECT) {
  224. queue->head = queue->tail = 0;  /* Flush input queue */
  225. return;
  226. }
  227. add_mouse_randomness(scancode);
  228. if (aux_count) {
  229. int head = queue->head;
  230. queue->buf[head] = scancode;
  231. head = (head + 1) & (AUX_BUF_SIZE-1);
  232. if (head != queue->tail) {
  233. queue->head = head;
  234. kill_fasync(&queue->fasync, SIGIO, POLL_IN);
  235. wake_up_interruptible(&queue->proc_list);
  236. }
  237. }
  238. }
  239. static inline int queue_empty(void)
  240. {
  241. return queue->head == queue->tail;
  242. }
  243. static unsigned char get_from_queue(void)
  244. {
  245. unsigned char result;
  246. unsigned long flags;
  247. spin_lock_irqsave(&kbd_controller_lock, flags);
  248. result = queue->buf[queue->tail];
  249. queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
  250. spin_unlock_irqrestore(&kbd_controller_lock, flags);
  251. return result;
  252. }
  253. /*
  254.  * Write to the aux device.
  255.  */
  256. static ssize_t write_aux(struct file * file, const char * buffer,
  257.  size_t count, loff_t *ppos)
  258. {
  259. ssize_t retval = 0;
  260. if (count) {
  261. ssize_t written = 0;
  262. if (count > 32)
  263. count = 32; /* Limit to 32 bytes. */
  264. do {
  265. char c;
  266. get_user(c, buffer++);
  267. written++;
  268. } while (--count);
  269. retval = -EIO;
  270. if (written) {
  271. retval = written;
  272. file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
  273. }
  274. }
  275. return retval;
  276. }
  277. static ssize_t read_aux(struct file * file, char * buffer,
  278. size_t count, loff_t *ppos)
  279. {
  280. DECLARE_WAITQUEUE(wait, current);
  281. ssize_t i = count;
  282. unsigned char c;
  283. if (queue_empty()) {
  284. if (file->f_flags & O_NONBLOCK)
  285. return -EAGAIN;
  286. add_wait_queue(&queue->proc_list, &wait);
  287. repeat:
  288. set_current_state(TASK_INTERRUPTIBLE);
  289. if (queue_empty() && !signal_pending(current)) {
  290. schedule();
  291. goto repeat;
  292. }
  293. current->state = TASK_RUNNING;
  294. remove_wait_queue(&queue->proc_list, &wait);
  295. }
  296. while (i > 0 && !queue_empty()) {
  297. c = get_from_queue();
  298. put_user(c, buffer++);
  299. i--;
  300. }
  301. if (count-i) {
  302. file->f_dentry->d_inode->i_atime = CURRENT_TIME;
  303. return count-i;
  304. }
  305. if (signal_pending(current))
  306. return -ERESTARTSYS;
  307. return 0;
  308. }
  309. static int open_aux(struct inode * inode, struct file * file)
  310. {
  311. if (aux_count++) 
  312. return 0;
  313. queue->head = queue->tail = 0; /* Flush input queue */
  314. aux_count = 1;
  315. aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
  316. return 0;
  317. }
  318. /* No kernel lock held - fine */
  319. static unsigned int aux_poll(struct file *file, poll_table * wait)
  320. {
  321. poll_wait(file, &queue->proc_list, wait);
  322. if (!queue_empty())
  323. return POLLIN | POLLRDNORM;
  324. return 0;
  325. }
  326. static int release_aux(struct inode * inode, struct file * file)
  327. {
  328. lock_kernel();
  329. fasync_aux(-1, file, 0);
  330. if (--aux_count) {
  331. unlock_kernel();
  332. return 0;
  333. }
  334. unlock_kernel();
  335. return 0;
  336. }
  337. static struct file_operations psaux_fops = {
  338. read: read_aux,
  339. write: write_aux,
  340. poll: aux_poll,
  341. open: open_aux,
  342. release: release_aux,
  343. fasync: fasync_aux,
  344. };
  345. static struct miscdevice psaux_mouse = {
  346. minor: PSMOUSE_MINOR,
  347. name: "psaux",
  348. fops: &psaux_fops,
  349. };
  350. #endif /* CONFIG_PSMOUSE */
  351. /* This function is looking at the PS2 controller and empty the two buffers */
  352. static u8 handle_lasikbd_event(unsigned long hpa)
  353. {
  354.         u8 status_keyb,status_mouse,scancode,id;
  355.         extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
  356.         
  357.         /* Mask to get the base address of the PS/2 controller */
  358.         id = gsc_readb(hpa+LASI_ID) & 0x0f;
  359.         
  360.         if (id==1) 
  361. hpa -= LASI_PSAUX_OFFSET; 
  362.         status_keyb = read_status(hpa);
  363.         status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
  364.         while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
  365.            
  366. while (status_keyb & LASI_STAT_RBNE) {
  367.       
  368. scancode = read_input(hpa);
  369.         /* XXX don't know if this is a valid fix, but filtering
  370.          * 0xfa avoids 'unknown scancode' errors on, eg, capslock
  371.          * on some keyboards.
  372.          */
  373.              
  374. if (scancode == AUX_REPLY_ACK) 
  375. cmd_status=0;
  376. else if (scancode == AUX_RESEND)
  377. cmd_status=1;
  378. else 
  379. handle_at_scancode(scancode); 
  380.       
  381. status_keyb =read_status(hpa);
  382. }
  383.    
  384. #ifdef CONFIG_PSMOUSE
  385. while (status_mouse & LASI_STAT_RBNE) {
  386. scancode = read_input(hpa+LASI_PSAUX_OFFSET);
  387. handle_mouse_scancode(scancode);
  388. status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
  389. }
  390. status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
  391. #endif /* CONFIG_PSMOUSE */
  392. status_keyb = read_status(hpa);
  393.         }
  394.         tasklet_schedule(&keyboard_tasklet);
  395.         return (status_keyb|status_mouse);
  396. }
  397. extern struct pt_regs *kbd_pt_regs;
  398. static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs)
  399. {
  400. kbd_pt_regs = regs;
  401. handle_lasikbd_event((unsigned long) dev);
  402. }
  403. extern int pckbd_translate(unsigned char, unsigned char *, char);
  404. extern int pckbd_setkeycode(unsigned int, unsigned int);
  405. extern int pckbd_getkeycode(unsigned int);
  406. static struct kbd_ops gsc_ps2_kbd_ops = {
  407. setkeycode:     pckbd_setkeycode,
  408.         getkeycode:     pckbd_getkeycode,
  409.         translate: pckbd_translate,
  410. leds: lasikbd_leds,
  411. #ifdef CONFIG_MAGIC_SYSRQ
  412. sysrq_key: 0x54,
  413. sysrq_xlate: hp_ps2kbd_sysrq_xlate,
  414. #endif
  415. };
  416. #if 1
  417. /* XXX: HACK !!!
  418.  * remove this function and the call in hil_kbd.c 
  419.  * if hp_psaux.c/hp_keyb.c is converted to the input layer... */
  420. int register_ps2_keybfuncs(void)
  421. {
  422. gsc_ps2_kbd_ops.leds = NULL;
  423. register_kbd_ops(&gsc_ps2_kbd_ops);
  424. }
  425. EXPORT_SYMBOL(register_ps2_keybfuncs);
  426. #endif
  427. static int __init
  428. lasi_ps2_register(struct parisc_device *dev)
  429. {
  430. unsigned long hpa = dev->hpa;
  431. char *name;
  432. int device_found = 0;
  433. u8 id;
  434. id = gsc_readb(hpa+LASI_ID) & 0x0f;
  435. switch (id) {
  436. case 0:
  437. name = "keyboard";
  438. lasikbd_hpa = hpa; /* save "hpa" for lasikbd_leds() */
  439. break;
  440. case 1:
  441. name = "psaux";
  442. break;
  443. default:
  444. printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.n",
  445. __FUNCTION__, id );
  446. return 0;
  447. }
  448. /* reset the PS/2 port */
  449. lasi_ps2_reset(hpa);
  450. switch (id) {
  451. case 0:
  452.         device_found = init_keyb(hpa);
  453. if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
  454. break;
  455. case 1:
  456. #ifdef CONFIG_PSMOUSE
  457. queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
  458. if (!queue)
  459. return -ENOMEM;
  460. memset(queue, 0, sizeof(*queue));
  461. queue->head = queue->tail = 0;
  462. init_waitqueue_head(&queue->proc_list);
  463. misc_register(&psaux_mouse);
  464. aux_write_ack(AUX_ENABLE_DEV);
  465. /* try it a second time, this will give status if the device is
  466.  * available */
  467. device_found = aux_write_ack(AUX_ENABLE_DEV);
  468. break;
  469. #else
  470. /* return without printing any unnecessary and misleading info */
  471. return 0;
  472. #endif
  473. } /* of case */
  474. if (device_found) {
  475. /* Here we claim only if we have a device attached */   
  476. /* allocate the irq and memory region for that device */
  477. if (!dev->irq)
  478.   return -ENODEV;
  479.    
  480.    if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
  481.    return -ENODEV;
  482.    
  483.    if (!request_mem_region(hpa, LASI_STATUS + 4, name))
  484.    return -ENODEV;
  485. }
  486. printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
  487.  "%sdevice attached.n",
  488. name, hpa, dev->irq, device_found ? "":"no ");
  489. return 0;
  490. }
  491. static struct parisc_device_id lasi_psaux_tbl[] = {
  492. { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 },
  493. { 0, } /* 0 terminated list */
  494. };
  495. MODULE_DEVICE_TABLE(parisc, lasi_psaux_tbl);
  496. static struct parisc_driver lasi_psaux_driver = {
  497. name: "Lasi psaux",
  498. id_table: lasi_psaux_tbl,
  499. probe: lasi_ps2_register,
  500. };
  501. static int __init gsc_ps2_init(void) 
  502. {
  503. return register_parisc_driver(&lasi_psaux_driver);
  504. }
  505. module_init(gsc_ps2_init);