cfsrvl.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (C) ST-Ericsson AB 2010
  3. * Author: Sjur Brendeland
  4. * License terms: GNU General Public License (GPL) version 2
  5. */
  6. #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/errno.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <linux/pkt_sched.h>
  13. #include <net/caif/caif_layer.h>
  14. #include <net/caif/cfsrvl.h>
  15. #include <net/caif/cfpkt.h>
  16. #include <net/caif/caif_dev.h>
  17. #define SRVL_CTRL_PKT_SIZE 1
  18. #define SRVL_FLOW_OFF 0x81
  19. #define SRVL_FLOW_ON 0x80
  20. #define SRVL_SET_PIN 0x82
  21. #define SRVL_CTRL_PKT_SIZE 1
  22. #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
  23. static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  24. int phyid)
  25. {
  26. struct cfsrvl *service = container_obj(layr);
  27. if (layr->up == NULL || layr->up->ctrlcmd == NULL)
  28. return;
  29. switch (ctrl) {
  30. case CAIF_CTRLCMD_INIT_RSP:
  31. service->open = true;
  32. layr->up->ctrlcmd(layr->up, ctrl, phyid);
  33. break;
  34. case CAIF_CTRLCMD_DEINIT_RSP:
  35. case CAIF_CTRLCMD_INIT_FAIL_RSP:
  36. service->open = false;
  37. layr->up->ctrlcmd(layr->up, ctrl, phyid);
  38. break;
  39. case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
  40. if (phyid != service->dev_info.id)
  41. break;
  42. if (service->modem_flow_on)
  43. layr->up->ctrlcmd(layr->up,
  44. CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  45. service->phy_flow_on = false;
  46. break;
  47. case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
  48. if (phyid != service->dev_info.id)
  49. return;
  50. if (service->modem_flow_on) {
  51. layr->up->ctrlcmd(layr->up,
  52. CAIF_CTRLCMD_FLOW_ON_IND,
  53. phyid);
  54. }
  55. service->phy_flow_on = true;
  56. break;
  57. case CAIF_CTRLCMD_FLOW_OFF_IND:
  58. if (service->phy_flow_on) {
  59. layr->up->ctrlcmd(layr->up,
  60. CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  61. }
  62. service->modem_flow_on = false;
  63. break;
  64. case CAIF_CTRLCMD_FLOW_ON_IND:
  65. if (service->phy_flow_on) {
  66. layr->up->ctrlcmd(layr->up,
  67. CAIF_CTRLCMD_FLOW_ON_IND, phyid);
  68. }
  69. service->modem_flow_on = true;
  70. break;
  71. case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
  72. /* In case interface is down, let's fake a remove shutdown */
  73. layr->up->ctrlcmd(layr->up,
  74. CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
  75. break;
  76. case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
  77. layr->up->ctrlcmd(layr->up, ctrl, phyid);
  78. break;
  79. default:
  80. pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
  81. /* We have both modem and phy flow on, send flow on */
  82. layr->up->ctrlcmd(layr->up, ctrl, phyid);
  83. service->phy_flow_on = true;
  84. break;
  85. }
  86. }
  87. static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
  88. {
  89. struct cfsrvl *service = container_obj(layr);
  90. caif_assert(layr != NULL);
  91. caif_assert(layr->dn != NULL);
  92. caif_assert(layr->dn->transmit != NULL);
  93. if (!service->supports_flowctrl)
  94. return 0;
  95. switch (ctrl) {
  96. case CAIF_MODEMCMD_FLOW_ON_REQ:
  97. {
  98. struct cfpkt *pkt;
  99. struct caif_payload_info *info;
  100. u8 flow_on = SRVL_FLOW_ON;
  101. pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
  102. if (!pkt)
  103. return -ENOMEM;
  104. if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
  105. pr_err("Packet is erroneous!\n");
  106. cfpkt_destroy(pkt);
  107. return -EPROTO;
  108. }
  109. info = cfpkt_info(pkt);
  110. info->channel_id = service->layer.id;
  111. info->hdr_len = 1;
  112. info->dev_info = &service->dev_info;
  113. cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
  114. return layr->dn->transmit(layr->dn, pkt);
  115. }
  116. case CAIF_MODEMCMD_FLOW_OFF_REQ:
  117. {
  118. struct cfpkt *pkt;
  119. struct caif_payload_info *info;
  120. u8 flow_off = SRVL_FLOW_OFF;
  121. pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
  122. if (!pkt)
  123. return -ENOMEM;
  124. if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
  125. pr_err("Packet is erroneous!\n");
  126. cfpkt_destroy(pkt);
  127. return -EPROTO;
  128. }
  129. info = cfpkt_info(pkt);
  130. info->channel_id = service->layer.id;
  131. info->hdr_len = 1;
  132. info->dev_info = &service->dev_info;
  133. cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
  134. return layr->dn->transmit(layr->dn, pkt);
  135. }
  136. default:
  137. break;
  138. }
  139. return -EINVAL;
  140. }
  141. static void cfsrvl_release(struct cflayer *layer)
  142. {
  143. struct cfsrvl *service = container_of(layer, struct cfsrvl, layer);
  144. kfree(service);
  145. }
  146. void cfsrvl_init(struct cfsrvl *service,
  147. u8 channel_id,
  148. struct dev_info *dev_info,
  149. bool supports_flowctrl)
  150. {
  151. caif_assert(offsetof(struct cfsrvl, layer) == 0);
  152. service->open = false;
  153. service->modem_flow_on = true;
  154. service->phy_flow_on = true;
  155. service->layer.id = channel_id;
  156. service->layer.ctrlcmd = cfservl_ctrlcmd;
  157. service->layer.modemcmd = cfservl_modemcmd;
  158. service->dev_info = *dev_info;
  159. service->supports_flowctrl = supports_flowctrl;
  160. service->release = cfsrvl_release;
  161. }
  162. bool cfsrvl_ready(struct cfsrvl *service, int *err)
  163. {
  164. if (!service->open) {
  165. *err = -ENOTCONN;
  166. return false;
  167. }
  168. return true;
  169. }
  170. u8 cfsrvl_getphyid(struct cflayer *layer)
  171. {
  172. struct cfsrvl *servl = container_obj(layer);
  173. return servl->dev_info.id;
  174. }
  175. bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
  176. {
  177. struct cfsrvl *servl = container_obj(layer);
  178. return servl->dev_info.id == phyid;
  179. }
  180. void caif_free_client(struct cflayer *adap_layer)
  181. {
  182. struct cfsrvl *servl;
  183. if (adap_layer == NULL || adap_layer->dn == NULL)
  184. return;
  185. servl = container_obj(adap_layer->dn);
  186. servl->release(&servl->layer);
  187. }
  188. EXPORT_SYMBOL(caif_free_client);
  189. void caif_client_register_refcnt(struct cflayer *adapt_layer,
  190. void (*hold)(struct cflayer *lyr),
  191. void (*put)(struct cflayer *lyr))
  192. {
  193. struct cfsrvl *service;
  194. if (WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL))
  195. return;
  196. service = container_of(adapt_layer->dn, struct cfsrvl, layer);
  197. service->hold = hold;
  198. service->put = put;
  199. }
  200. EXPORT_SYMBOL(caif_client_register_refcnt);