ps2mult.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * TQC PS/2 Multiplexer driver
  3. *
  4. * Copyright (C) 2010 Dmitry Eremin-Solenikov
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/slab.h>
  12. #include <linux/module.h>
  13. #include <linux/serio.h>
  14. MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
  15. MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
  16. MODULE_LICENSE("GPL");
  17. #define PS2MULT_KB_SELECTOR 0xA0
  18. #define PS2MULT_MS_SELECTOR 0xA1
  19. #define PS2MULT_ESCAPE 0x7D
  20. #define PS2MULT_BSYNC 0x7E
  21. #define PS2MULT_SESSION_START 0x55
  22. #define PS2MULT_SESSION_END 0x56
  23. struct ps2mult_port {
  24. struct serio *serio;
  25. unsigned char sel;
  26. bool registered;
  27. };
  28. #define PS2MULT_NUM_PORTS 2
  29. #define PS2MULT_KBD_PORT 0
  30. #define PS2MULT_MOUSE_PORT 1
  31. struct ps2mult {
  32. struct serio *mx_serio;
  33. struct ps2mult_port ports[PS2MULT_NUM_PORTS];
  34. spinlock_t lock;
  35. struct ps2mult_port *in_port;
  36. struct ps2mult_port *out_port;
  37. bool escape;
  38. };
  39. /* First MUST come PS2MULT_NUM_PORTS selectors */
  40. static const unsigned char ps2mult_controls[] = {
  41. PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
  42. PS2MULT_ESCAPE, PS2MULT_BSYNC,
  43. PS2MULT_SESSION_START, PS2MULT_SESSION_END,
  44. };
  45. static const struct serio_device_id ps2mult_serio_ids[] = {
  46. {
  47. .type = SERIO_RS232,
  48. .proto = SERIO_PS2MULT,
  49. .id = SERIO_ANY,
  50. .extra = SERIO_ANY,
  51. },
  52. { 0 }
  53. };
  54. MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
  55. static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
  56. {
  57. struct serio *mx_serio = psm->mx_serio;
  58. serio_write(mx_serio, port->sel);
  59. psm->out_port = port;
  60. dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
  61. }
  62. static int ps2mult_serio_write(struct serio *serio, unsigned char data)
  63. {
  64. struct serio *mx_port = serio->parent;
  65. struct ps2mult *psm = serio_get_drvdata(mx_port);
  66. struct ps2mult_port *port = serio->port_data;
  67. bool need_escape;
  68. unsigned long flags;
  69. spin_lock_irqsave(&psm->lock, flags);
  70. if (psm->out_port != port)
  71. ps2mult_select_port(psm, port);
  72. need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
  73. dev_dbg(&serio->dev,
  74. "write: %s%02x\n", need_escape ? "ESC " : "", data);
  75. if (need_escape)
  76. serio_write(mx_port, PS2MULT_ESCAPE);
  77. serio_write(mx_port, data);
  78. spin_unlock_irqrestore(&psm->lock, flags);
  79. return 0;
  80. }
  81. static int ps2mult_serio_start(struct serio *serio)
  82. {
  83. struct ps2mult *psm = serio_get_drvdata(serio->parent);
  84. struct ps2mult_port *port = serio->port_data;
  85. unsigned long flags;
  86. spin_lock_irqsave(&psm->lock, flags);
  87. port->registered = true;
  88. spin_unlock_irqrestore(&psm->lock, flags);
  89. return 0;
  90. }
  91. static void ps2mult_serio_stop(struct serio *serio)
  92. {
  93. struct ps2mult *psm = serio_get_drvdata(serio->parent);
  94. struct ps2mult_port *port = serio->port_data;
  95. unsigned long flags;
  96. spin_lock_irqsave(&psm->lock, flags);
  97. port->registered = false;
  98. spin_unlock_irqrestore(&psm->lock, flags);
  99. }
  100. static int ps2mult_create_port(struct ps2mult *psm, int i)
  101. {
  102. struct serio *mx_serio = psm->mx_serio;
  103. struct serio *serio;
  104. serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
  105. if (!serio)
  106. return -ENOMEM;
  107. strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
  108. snprintf(serio->phys, sizeof(serio->phys),
  109. "%s/port%d", mx_serio->phys, i);
  110. serio->id.type = SERIO_8042;
  111. serio->write = ps2mult_serio_write;
  112. serio->start = ps2mult_serio_start;
  113. serio->stop = ps2mult_serio_stop;
  114. serio->parent = psm->mx_serio;
  115. serio->port_data = &psm->ports[i];
  116. psm->ports[i].serio = serio;
  117. return 0;
  118. }
  119. static void ps2mult_reset(struct ps2mult *psm)
  120. {
  121. unsigned long flags;
  122. spin_lock_irqsave(&psm->lock, flags);
  123. serio_write(psm->mx_serio, PS2MULT_SESSION_END);
  124. serio_write(psm->mx_serio, PS2MULT_SESSION_START);
  125. ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
  126. spin_unlock_irqrestore(&psm->lock, flags);
  127. }
  128. static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
  129. {
  130. struct ps2mult *psm;
  131. int i;
  132. int error;
  133. if (!serio->write)
  134. return -EINVAL;
  135. psm = kzalloc(sizeof(*psm), GFP_KERNEL);
  136. if (!psm)
  137. return -ENOMEM;
  138. spin_lock_init(&psm->lock);
  139. psm->mx_serio = serio;
  140. for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
  141. psm->ports[i].sel = ps2mult_controls[i];
  142. error = ps2mult_create_port(psm, i);
  143. if (error)
  144. goto err_out;
  145. }
  146. psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
  147. serio_set_drvdata(serio, psm);
  148. error = serio_open(serio, drv);
  149. if (error)
  150. goto err_out;
  151. ps2mult_reset(psm);
  152. for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
  153. struct serio *s = psm->ports[i].serio;
  154. dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
  155. serio_register_port(s);
  156. }
  157. return 0;
  158. err_out:
  159. while (--i >= 0)
  160. kfree(psm->ports[i].serio);
  161. kfree(psm);
  162. return error;
  163. }
  164. static void ps2mult_disconnect(struct serio *serio)
  165. {
  166. struct ps2mult *psm = serio_get_drvdata(serio);
  167. /* Note that serio core already take care of children ports */
  168. serio_write(serio, PS2MULT_SESSION_END);
  169. serio_close(serio);
  170. kfree(psm);
  171. serio_set_drvdata(serio, NULL);
  172. }
  173. static int ps2mult_reconnect(struct serio *serio)
  174. {
  175. struct ps2mult *psm = serio_get_drvdata(serio);
  176. ps2mult_reset(psm);
  177. return 0;
  178. }
  179. static irqreturn_t ps2mult_interrupt(struct serio *serio,
  180. unsigned char data, unsigned int dfl)
  181. {
  182. struct ps2mult *psm = serio_get_drvdata(serio);
  183. struct ps2mult_port *in_port;
  184. unsigned long flags;
  185. dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
  186. spin_lock_irqsave(&psm->lock, flags);
  187. if (psm->escape) {
  188. psm->escape = false;
  189. in_port = psm->in_port;
  190. if (in_port->registered)
  191. serio_interrupt(in_port->serio, data, dfl);
  192. goto out;
  193. }
  194. switch (data) {
  195. case PS2MULT_ESCAPE:
  196. dev_dbg(&serio->dev, "ESCAPE\n");
  197. psm->escape = true;
  198. break;
  199. case PS2MULT_BSYNC:
  200. dev_dbg(&serio->dev, "BSYNC\n");
  201. psm->in_port = psm->out_port;
  202. break;
  203. case PS2MULT_SESSION_START:
  204. dev_dbg(&serio->dev, "SS\n");
  205. break;
  206. case PS2MULT_SESSION_END:
  207. dev_dbg(&serio->dev, "SE\n");
  208. break;
  209. case PS2MULT_KB_SELECTOR:
  210. dev_dbg(&serio->dev, "KB\n");
  211. psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
  212. break;
  213. case PS2MULT_MS_SELECTOR:
  214. dev_dbg(&serio->dev, "MS\n");
  215. psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
  216. break;
  217. default:
  218. in_port = psm->in_port;
  219. if (in_port->registered)
  220. serio_interrupt(in_port->serio, data, dfl);
  221. break;
  222. }
  223. out:
  224. spin_unlock_irqrestore(&psm->lock, flags);
  225. return IRQ_HANDLED;
  226. }
  227. static struct serio_driver ps2mult_drv = {
  228. .driver = {
  229. .name = "ps2mult",
  230. },
  231. .description = "TQC PS/2 Multiplexer driver",
  232. .id_table = ps2mult_serio_ids,
  233. .interrupt = ps2mult_interrupt,
  234. .connect = ps2mult_connect,
  235. .disconnect = ps2mult_disconnect,
  236. .reconnect = ps2mult_reconnect,
  237. };
  238. module_serio_driver(ps2mult_drv);