linux/net/nfc/hci/hcp.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012  Intel Corporation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the
  16 * Free Software Foundation, Inc.,
  17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18 */
  19
  20#define pr_fmt(fmt) "hci: %s: " fmt, __func__
  21
  22#include <linux/init.h>
  23#include <linux/kernel.h>
  24#include <linux/module.h>
  25
  26#include <net/nfc/hci.h>
  27
  28#include "hci.h"
  29
  30/*
  31 * Payload is the HCP message data only. Instruction will be prepended.
  32 * Guarantees that cb will be called upon completion or timeout delay
  33 * counted from the moment the cmd is sent to the transport.
  34 */
  35int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
  36                           u8 type, u8 instruction,
  37                           const u8 *payload, size_t payload_len,
  38                           data_exchange_cb_t cb, void *cb_context,
  39                           unsigned long completion_delay)
  40{
  41        struct nfc_dev *ndev = hdev->ndev;
  42        struct hci_msg *cmd;
  43        const u8 *ptr = payload;
  44        int hci_len, err;
  45        bool firstfrag = true;
  46
  47        cmd = kzalloc(sizeof(struct hci_msg), GFP_KERNEL);
  48        if (cmd == NULL)
  49                return -ENOMEM;
  50
  51        INIT_LIST_HEAD(&cmd->msg_l);
  52        skb_queue_head_init(&cmd->msg_frags);
  53        cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false;
  54        cmd->cb = cb;
  55        cmd->cb_context = cb_context;
  56        cmd->completion_delay = completion_delay;
  57
  58        hci_len = payload_len + 1;
  59        while (hci_len > 0) {
  60                struct sk_buff *skb;
  61                int skb_len, data_link_len;
  62                struct hcp_packet *packet;
  63
  64                if (NFC_HCI_HCP_PACKET_HEADER_LEN + hci_len <=
  65                    hdev->max_data_link_payload)
  66                        data_link_len = hci_len;
  67                else
  68                        data_link_len = hdev->max_data_link_payload -
  69                                        NFC_HCI_HCP_PACKET_HEADER_LEN;
  70
  71                skb_len = ndev->tx_headroom + NFC_HCI_HCP_PACKET_HEADER_LEN +
  72                          data_link_len + ndev->tx_tailroom;
  73                hci_len -= data_link_len;
  74
  75                skb = alloc_skb(skb_len, GFP_KERNEL);
  76                if (skb == NULL) {
  77                        err = -ENOMEM;
  78                        goto out_skb_err;
  79                }
  80                skb_reserve(skb, ndev->tx_headroom);
  81
  82                skb_put(skb, NFC_HCI_HCP_PACKET_HEADER_LEN + data_link_len);
  83
  84                /* Only the last fragment will have the cb bit set to 1 */
  85                packet = (struct hcp_packet *)skb->data;
  86                packet->header = pipe;
  87                if (firstfrag) {
  88                        firstfrag = false;
  89                        packet->message.header = HCP_HEADER(type, instruction);
  90                        if (ptr) {
  91                                memcpy(packet->message.data, ptr,
  92                                       data_link_len - 1);
  93                                ptr += data_link_len - 1;
  94                        }
  95                } else {
  96                        memcpy(&packet->message, ptr, data_link_len);
  97                        ptr += data_link_len;
  98                }
  99
 100                /* This is the last fragment, set the cb bit */
 101                if (hci_len == 0)
 102                        packet->header |= ~NFC_HCI_FRAGMENT;
 103
 104                skb_queue_tail(&cmd->msg_frags, skb);
 105        }
 106
 107        mutex_lock(&hdev->msg_tx_mutex);
 108
 109        if (hdev->shutting_down) {
 110                err = -ESHUTDOWN;
 111                mutex_unlock(&hdev->msg_tx_mutex);
 112                goto out_skb_err;
 113        }
 114
 115        list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
 116        mutex_unlock(&hdev->msg_tx_mutex);
 117
 118        schedule_work(&hdev->msg_tx_work);
 119
 120        return 0;
 121
 122out_skb_err:
 123        skb_queue_purge(&cmd->msg_frags);
 124        kfree(cmd);
 125
 126        return err;
 127}
 128
 129u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe)
 130{
 131        int gate;
 132
 133        for (gate = 0; gate < NFC_HCI_MAX_GATES; gate++)
 134                if (hdev->gate2pipe[gate] == pipe)
 135                        return gate;
 136
 137        return 0xff;
 138}
 139
 140/*
 141 * Receive hcp message for pipe, with type and cmd.
 142 * skb contains optional message data only.
 143 */
 144void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type,
 145                            u8 instruction, struct sk_buff *skb)
 146{
 147        switch (type) {
 148        case NFC_HCI_HCP_RESPONSE:
 149                nfc_hci_resp_received(hdev, instruction, skb);
 150                break;
 151        case NFC_HCI_HCP_COMMAND:
 152                nfc_hci_cmd_received(hdev, pipe, instruction, skb);
 153                break;
 154        case NFC_HCI_HCP_EVENT:
 155                nfc_hci_event_received(hdev, pipe, instruction, skb);
 156                break;
 157        default:
 158                pr_err("UNKNOWN MSG Type %d, instruction=%d\n",
 159                       type, instruction);
 160                kfree_skb(skb);
 161                break;
 162        }
 163}
 164