smsgiucv.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * IUCV special message driver
  3. *
  4. * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
  5. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2, or (at your option)
  10. * any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <linux/module.h>
  22. #include <linux/init.h>
  23. #include <linux/errno.h>
  24. #include <linux/device.h>
  25. #include <asm/cpcmd.h>
  26. #include <asm/ebcdic.h>
  27. #include "iucv.h"
  28. struct smsg_callback {
  29. struct list_head list;
  30. char *prefix;
  31. int len;
  32. void (*callback)(char *from, char *str);
  33. };
  34. MODULE_AUTHOR
  35. ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
  36. MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
  37. static iucv_handle_t smsg_handle;
  38. static unsigned short smsg_pathid;
  39. static DEFINE_SPINLOCK(smsg_list_lock);
  40. static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
  41. static void
  42. smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
  43. {
  44. }
  45. static void
  46. smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
  47. {
  48. struct smsg_callback *cb;
  49. unsigned char *msg;
  50. unsigned char sender[9];
  51. unsigned short len;
  52. int rc, i;
  53. len = eib->ln1msg2.ipbfln1f;
  54. msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
  55. if (!msg) {
  56. iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
  57. return;
  58. }
  59. rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
  60. msg, len, 0, 0, 0);
  61. if (rc == 0) {
  62. msg[len] = 0;
  63. EBCASC(msg, len);
  64. memcpy(sender, msg, 8);
  65. sender[8] = 0;
  66. /* Remove trailing whitespace from the sender name. */
  67. for (i = 7; i >= 0; i--) {
  68. if (sender[i] != ' ' && sender[i] != '\t')
  69. break;
  70. sender[i] = 0;
  71. }
  72. spin_lock(&smsg_list_lock);
  73. list_for_each_entry(cb, &smsg_list, list)
  74. if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
  75. cb->callback(sender, msg + 8);
  76. break;
  77. }
  78. spin_unlock(&smsg_list_lock);
  79. }
  80. kfree(msg);
  81. }
  82. static iucv_interrupt_ops_t smsg_ops = {
  83. .ConnectionComplete = smsg_connection_complete,
  84. .MessagePending = smsg_message_pending,
  85. };
  86. static struct device_driver smsg_driver = {
  87. .name = "SMSGIUCV",
  88. .bus = &iucv_bus,
  89. };
  90. int
  91. smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
  92. {
  93. struct smsg_callback *cb;
  94. cb = kmalloc(sizeof(struct smsg_callback), GFP_KERNEL);
  95. if (!cb)
  96. return -ENOMEM;
  97. cb->prefix = prefix;
  98. cb->len = strlen(prefix);
  99. cb->callback = callback;
  100. spin_lock(&smsg_list_lock);
  101. list_add_tail(&cb->list, &smsg_list);
  102. spin_unlock(&smsg_list_lock);
  103. return 0;
  104. }
  105. void
  106. smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
  107. {
  108. struct smsg_callback *cb, *tmp;
  109. spin_lock(&smsg_list_lock);
  110. cb = 0;
  111. list_for_each_entry(tmp, &smsg_list, list)
  112. if (tmp->callback == callback &&
  113. strcmp(tmp->prefix, prefix) == 0) {
  114. cb = tmp;
  115. list_del(&cb->list);
  116. break;
  117. }
  118. spin_unlock(&smsg_list_lock);
  119. kfree(cb);
  120. }
  121. static void __exit
  122. smsg_exit(void)
  123. {
  124. if (smsg_handle > 0) {
  125. cpcmd("SET SMSG OFF", NULL, 0, NULL);
  126. iucv_sever(smsg_pathid, 0);
  127. iucv_unregister_program(smsg_handle);
  128. driver_unregister(&smsg_driver);
  129. }
  130. return;
  131. }
  132. static int __init
  133. smsg_init(void)
  134. {
  135. static unsigned char pgmmask[24] = {
  136. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  137. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  138. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  139. };
  140. int rc;
  141. rc = driver_register(&smsg_driver);
  142. if (rc != 0) {
  143. printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
  144. return rc;
  145. }
  146. smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
  147. pgmmask, &smsg_ops, 0);
  148. if (!smsg_handle) {
  149. printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
  150. driver_unregister(&smsg_driver);
  151. return -EIO; /* better errno ? */
  152. }
  153. rc = iucv_connect (&smsg_pathid, 255, 0, "*MSG ", 0, 0, 0, 0,
  154. smsg_handle, 0);
  155. if (rc) {
  156. printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
  157. iucv_unregister_program(smsg_handle);
  158. driver_unregister(&smsg_driver);
  159. smsg_handle = 0;
  160. return -EIO;
  161. }
  162. cpcmd("SET SMSG IUCV", NULL, 0, NULL);
  163. return 0;
  164. }
  165. module_init(smsg_init);
  166. module_exit(smsg_exit);
  167. MODULE_LICENSE("GPL");
  168. EXPORT_SYMBOL(smsg_register_callback);
  169. EXPORT_SYMBOL(smsg_unregister_callback);