cfrfml.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (C) ST-Ericsson AB 2010
  3. * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
  4. * License terms: GNU General Public License (GPL) version 2
  5. */
  6. #include <linux/stddef.h>
  7. #include <linux/spinlock.h>
  8. #include <linux/slab.h>
  9. #include <net/caif/caif_layer.h>
  10. #include <net/caif/cfsrvl.h>
  11. #include <net/caif/cfpkt.h>
  12. #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
  13. #define RFM_SEGMENTATION_BIT 0x01
  14. #define RFM_PAYLOAD 0x00
  15. #define RFM_CMD_BIT 0x80
  16. #define RFM_FLOW_OFF 0x81
  17. #define RFM_FLOW_ON 0x80
  18. #define RFM_SET_PIN 0x82
  19. #define RFM_CTRL_PKT_SIZE 1
  20. static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
  21. static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
  22. struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info)
  23. {
  24. struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
  25. if (!rfm) {
  26. pr_warning("CAIF: %s(): Out of memory\n", __func__);
  27. return NULL;
  28. }
  29. caif_assert(offsetof(struct cfsrvl, layer) == 0);
  30. memset(rfm, 0, sizeof(struct cfsrvl));
  31. cfsrvl_init(rfm, channel_id, dev_info, false);
  32. rfm->layer.receive = cfrfml_receive;
  33. rfm->layer.transmit = cfrfml_transmit;
  34. snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
  35. return &rfm->layer;
  36. }
  37. static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
  38. {
  39. u8 tmp;
  40. bool segmented;
  41. int ret;
  42. caif_assert(layr->up != NULL);
  43. caif_assert(layr->receive != NULL);
  44. /*
  45. * RFM is taking care of segmentation and stripping of
  46. * segmentation bit.
  47. */
  48. if (cfpkt_extr_head(pkt, &tmp, 1) < 0) {
  49. pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
  50. cfpkt_destroy(pkt);
  51. return -EPROTO;
  52. }
  53. segmented = tmp & RFM_SEGMENTATION_BIT;
  54. caif_assert(!segmented);
  55. ret = layr->up->receive(layr->up, pkt);
  56. return ret;
  57. }
  58. static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
  59. {
  60. u8 tmp = 0;
  61. int ret;
  62. struct cfsrvl *service = container_obj(layr);
  63. caif_assert(layr->dn != NULL);
  64. caif_assert(layr->dn->transmit != NULL);
  65. if (!cfsrvl_ready(service, &ret))
  66. return ret;
  67. if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
  68. pr_err("CAIF: %s():Packet too large - size=%d\n",
  69. __func__, cfpkt_getlen(pkt));
  70. return -EOVERFLOW;
  71. }
  72. if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
  73. pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
  74. return -EPROTO;
  75. }
  76. /* Add info for MUX-layer to route the packet out. */
  77. cfpkt_info(pkt)->channel_id = service->layer.id;
  78. /*
  79. * To optimize alignment, we add up the size of CAIF header before
  80. * payload.
  81. */
  82. cfpkt_info(pkt)->hdr_len = 1;
  83. cfpkt_info(pkt)->dev_info = &service->dev_info;
  84. ret = layr->dn->transmit(layr->dn, pkt);
  85. if (ret < 0)
  86. cfpkt_extr_head(pkt, &tmp, 1);
  87. return ret;
  88. }