parkbd.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Parallel port to Keyboard port adapter driver for Linux
  3. *
  4. * Copyright (c) 1999-2004 Vojtech Pavlik
  5. */
  6. /*
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published by
  9. * the Free Software Foundation.
  10. */
  11. /*
  12. * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter
  13. * can be made:
  14. *
  15. * Parallel port Keyboard port
  16. *
  17. * +5V --------------------- +5V (4)
  18. *
  19. * ______
  20. * +5V -------|______|--.
  21. * |
  22. * ACK (10) ------------|
  23. * |--- KBD CLOCK (5)
  24. * STROBE (1) ---|<|----'
  25. *
  26. * ______
  27. * +5V -------|______|--.
  28. * |
  29. * BUSY (11) -----------|
  30. * |--- KBD DATA (1)
  31. * AUTOFD (14) --|<|----'
  32. *
  33. * GND (18-25) ------------- GND (3)
  34. *
  35. * The diodes can be fairly any type, and the resistors should be somewhere
  36. * around 5 kOhm, but the adapter will likely work without the resistors,
  37. * too.
  38. *
  39. * The +5V source can be taken either from USB, from mouse or keyboard ports,
  40. * or from a joystick port. Unfortunately, the parallel port of a PC doesn't
  41. * have a +5V pin, and feeding the keyboard from signal pins is out of question
  42. * with 300 mA power reqirement of a typical AT keyboard.
  43. */
  44. #include <linux/module.h>
  45. #include <linux/parport.h>
  46. #include <linux/slab.h>
  47. #include <linux/init.h>
  48. #include <linux/serio.h>
  49. MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  50. MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
  51. MODULE_LICENSE("GPL");
  52. static unsigned int parkbd_pp_no;
  53. module_param_named(port, parkbd_pp_no, int, 0);
  54. MODULE_PARM_DESC(port, "Parallel port the adapter is connected to (default is 0)");
  55. static unsigned int parkbd_mode = SERIO_8042;
  56. module_param_named(mode, parkbd_mode, uint, 0);
  57. MODULE_PARM_DESC(mode, "Mode of operation: XT = 0/AT = 1 (default)");
  58. #define PARKBD_CLOCK 0x01 /* Strobe & Ack */
  59. #define PARKBD_DATA 0x02 /* AutoFd & Busy */
  60. static int parkbd_buffer;
  61. static int parkbd_counter;
  62. static unsigned long parkbd_last;
  63. static int parkbd_writing;
  64. static unsigned long parkbd_start;
  65. static struct pardevice *parkbd_dev;
  66. static struct serio *parkbd_port;
  67. static int parkbd_readlines(void)
  68. {
  69. return (parport_read_status(parkbd_dev->port) >> 6) ^ 2;
  70. }
  71. static void parkbd_writelines(int data)
  72. {
  73. parport_write_control(parkbd_dev->port, (~data & 3) | 0x10);
  74. }
  75. static int parkbd_write(struct serio *port, unsigned char c)
  76. {
  77. unsigned char p;
  78. if (!parkbd_mode) return -1;
  79. p = c ^ (c >> 4);
  80. p = p ^ (p >> 2);
  81. p = p ^ (p >> 1);
  82. parkbd_counter = 0;
  83. parkbd_writing = 1;
  84. parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600;
  85. parkbd_writelines(2);
  86. return 0;
  87. }
  88. static void parkbd_interrupt(void *dev_id)
  89. {
  90. if (parkbd_writing) {
  91. if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) {
  92. parkbd_counter = 0;
  93. parkbd_buffer = 0;
  94. parkbd_writing = 0;
  95. parkbd_writelines(3);
  96. return;
  97. }
  98. parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
  99. if (parkbd_counter == 11) {
  100. parkbd_counter = 0;
  101. parkbd_buffer = 0;
  102. parkbd_writing = 0;
  103. parkbd_writelines(3);
  104. }
  105. } else {
  106. if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
  107. parkbd_counter = 0;
  108. parkbd_buffer = 0;
  109. }
  110. parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
  111. if (parkbd_counter == parkbd_mode + 10)
  112. serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
  113. }
  114. parkbd_last = jiffies;
  115. }
  116. static int parkbd_getport(struct parport *pp)
  117. {
  118. struct pardev_cb parkbd_parport_cb;
  119. memset(&parkbd_parport_cb, 0, sizeof(parkbd_parport_cb));
  120. parkbd_parport_cb.irq_func = parkbd_interrupt;
  121. parkbd_parport_cb.flags = PARPORT_FLAG_EXCL;
  122. parkbd_dev = parport_register_dev_model(pp, "parkbd",
  123. &parkbd_parport_cb, 0);
  124. if (!parkbd_dev)
  125. return -ENODEV;
  126. if (parport_claim(parkbd_dev)) {
  127. parport_unregister_device(parkbd_dev);
  128. return -EBUSY;
  129. }
  130. parkbd_start = jiffies;
  131. return 0;
  132. }
  133. static struct serio *parkbd_allocate_serio(void)
  134. {
  135. struct serio *serio;
  136. serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
  137. if (serio) {
  138. serio->id.type = parkbd_mode;
  139. serio->write = parkbd_write,
  140. strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
  141. snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name);
  142. }
  143. return serio;
  144. }
  145. static void parkbd_attach(struct parport *pp)
  146. {
  147. if (pp->number != parkbd_pp_no) {
  148. pr_debug("Not using parport%d.\n", pp->number);
  149. return;
  150. }
  151. if (parkbd_getport(pp))
  152. return;
  153. parkbd_port = parkbd_allocate_serio();
  154. if (!parkbd_port) {
  155. parport_release(parkbd_dev);
  156. parport_unregister_device(parkbd_dev);
  157. return;
  158. }
  159. parkbd_writelines(3);
  160. serio_register_port(parkbd_port);
  161. printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
  162. parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
  163. return;
  164. }
  165. static void parkbd_detach(struct parport *port)
  166. {
  167. if (!parkbd_port || port->number != parkbd_pp_no)
  168. return;
  169. parport_release(parkbd_dev);
  170. serio_unregister_port(parkbd_port);
  171. parport_unregister_device(parkbd_dev);
  172. parkbd_port = NULL;
  173. }
  174. static struct parport_driver parkbd_parport_driver = {
  175. .name = "parkbd",
  176. .match_port = parkbd_attach,
  177. .detach = parkbd_detach,
  178. .devmodel = true,
  179. };
  180. static int __init parkbd_init(void)
  181. {
  182. return parport_register_driver(&parkbd_parport_driver);
  183. }
  184. static void __exit parkbd_exit(void)
  185. {
  186. parport_unregister_driver(&parkbd_parport_driver);
  187. }
  188. module_init(parkbd_init);
  189. module_exit(parkbd_exit);