linux/drivers/nfc/st-nci/ndlc.c
<<
>>
Prefs
   1/*
   2 * Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip
   3 *
   4 * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include <linux/sched.h>
  20#include <net/nfc/nci_core.h>
  21
  22#include "st-nci.h"
  23
  24#define NDLC_TIMER_T1           100
  25#define NDLC_TIMER_T1_WAIT      400
  26#define NDLC_TIMER_T2           1200
  27
  28#define PCB_TYPE_DATAFRAME              0x80
  29#define PCB_TYPE_SUPERVISOR             0xc0
  30#define PCB_TYPE_MASK                   PCB_TYPE_SUPERVISOR
  31
  32#define PCB_SYNC_ACK                    0x20
  33#define PCB_SYNC_NACK                   0x10
  34#define PCB_SYNC_WAIT                   0x30
  35#define PCB_SYNC_NOINFO                 0x00
  36#define PCB_SYNC_MASK                   PCB_SYNC_WAIT
  37
  38#define PCB_DATAFRAME_RETRANSMIT_YES    0x00
  39#define PCB_DATAFRAME_RETRANSMIT_NO     0x04
  40#define PCB_DATAFRAME_RETRANSMIT_MASK   PCB_DATAFRAME_RETRANSMIT_NO
  41
  42#define PCB_SUPERVISOR_RETRANSMIT_YES   0x00
  43#define PCB_SUPERVISOR_RETRANSMIT_NO    0x02
  44#define PCB_SUPERVISOR_RETRANSMIT_MASK  PCB_SUPERVISOR_RETRANSMIT_NO
  45
  46#define PCB_FRAME_CRC_INFO_PRESENT      0x08
  47#define PCB_FRAME_CRC_INFO_NOTPRESENT   0x00
  48#define PCB_FRAME_CRC_INFO_MASK         PCB_FRAME_CRC_INFO_PRESENT
  49
  50#define NDLC_DUMP_SKB(info, skb)                                 \
  51do {                                                             \
  52        pr_debug("%s:\n", info);                                 \
  53        print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \
  54                        16, 1, skb->data, skb->len, 0);          \
  55} while (0)
  56
  57int ndlc_open(struct llt_ndlc *ndlc)
  58{
  59        /* toggle reset pin */
  60        ndlc->ops->enable(ndlc->phy_id);
  61        ndlc->powered = 1;
  62        return 0;
  63}
  64EXPORT_SYMBOL(ndlc_open);
  65
  66void ndlc_close(struct llt_ndlc *ndlc)
  67{
  68        struct nci_mode_set_cmd cmd;
  69
  70        cmd.cmd_type = ST_NCI_SET_NFC_MODE;
  71        cmd.mode = 0;
  72
  73        /* toggle reset pin */
  74        ndlc->ops->enable(ndlc->phy_id);
  75
  76        nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP,
  77                     sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd);
  78
  79        ndlc->powered = 0;
  80        ndlc->ops->disable(ndlc->phy_id);
  81}
  82EXPORT_SYMBOL(ndlc_close);
  83
  84int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb)
  85{
  86        /* add ndlc header */
  87        u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO |
  88                PCB_FRAME_CRC_INFO_NOTPRESENT;
  89
  90        *(u8 *)skb_push(skb, 1) = pcb;
  91        skb_queue_tail(&ndlc->send_q, skb);
  92
  93        schedule_work(&ndlc->sm_work);
  94
  95        return 0;
  96}
  97EXPORT_SYMBOL(ndlc_send);
  98
  99static void llt_ndlc_send_queue(struct llt_ndlc *ndlc)
 100{
 101        struct sk_buff *skb;
 102        int r;
 103        unsigned long time_sent;
 104
 105        if (ndlc->send_q.qlen)
 106                pr_debug("sendQlen=%d unackQlen=%d\n",
 107                         ndlc->send_q.qlen, ndlc->ack_pending_q.qlen);
 108
 109        while (ndlc->send_q.qlen) {
 110                skb = skb_dequeue(&ndlc->send_q);
 111                NDLC_DUMP_SKB("ndlc frame written", skb);
 112                r = ndlc->ops->write(ndlc->phy_id, skb);
 113                if (r < 0) {
 114                        ndlc->hard_fault = r;
 115                        break;
 116                }
 117                time_sent = jiffies;
 118                *(unsigned long *)skb->cb = time_sent;
 119
 120                skb_queue_tail(&ndlc->ack_pending_q, skb);
 121
 122                /* start timer t1 for ndlc aknowledge */
 123                ndlc->t1_active = true;
 124                mod_timer(&ndlc->t1_timer, time_sent +
 125                        msecs_to_jiffies(NDLC_TIMER_T1));
 126                /* start timer t2 for chip availability */
 127                ndlc->t2_active = true;
 128                mod_timer(&ndlc->t2_timer, time_sent +
 129                        msecs_to_jiffies(NDLC_TIMER_T2));
 130        }
 131}
 132
 133static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
 134{
 135        struct sk_buff *skb;
 136        u8 pcb;
 137
 138        while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) {
 139                pcb = skb->data[0];
 140                switch (pcb & PCB_TYPE_MASK) {
 141                case PCB_TYPE_SUPERVISOR:
 142                        skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) |
 143                                PCB_SUPERVISOR_RETRANSMIT_YES;
 144                        break;
 145                case PCB_TYPE_DATAFRAME:
 146                        skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) |
 147                                PCB_DATAFRAME_RETRANSMIT_YES;
 148                        break;
 149                default:
 150                        pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
 151                        kfree_skb(skb);
 152                        continue;
 153                }
 154                skb_queue_head(&ndlc->send_q, skb);
 155        }
 156}
 157
 158static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc)
 159{
 160        struct sk_buff *skb;
 161        u8 pcb;
 162        unsigned long time_sent;
 163
 164        if (ndlc->rcv_q.qlen)
 165                pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen);
 166
 167        while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) {
 168                pcb = skb->data[0];
 169                skb_pull(skb, 1);
 170                if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) {
 171                        switch (pcb & PCB_SYNC_MASK) {
 172                        case PCB_SYNC_ACK:
 173                                skb = skb_dequeue(&ndlc->ack_pending_q);
 174                                kfree_skb(skb);
 175                                del_timer_sync(&ndlc->t1_timer);
 176                                del_timer_sync(&ndlc->t2_timer);
 177                                ndlc->t2_active = false;
 178                                ndlc->t1_active = false;
 179                                break;
 180                        case PCB_SYNC_NACK:
 181                                llt_ndlc_requeue_data_pending(ndlc);
 182                                llt_ndlc_send_queue(ndlc);
 183                                /* start timer t1 for ndlc aknowledge */
 184                                time_sent = jiffies;
 185                                ndlc->t1_active = true;
 186                                mod_timer(&ndlc->t1_timer, time_sent +
 187                                        msecs_to_jiffies(NDLC_TIMER_T1));
 188                                break;
 189                        case PCB_SYNC_WAIT:
 190                                time_sent = jiffies;
 191                                ndlc->t1_active = true;
 192                                mod_timer(&ndlc->t1_timer, time_sent +
 193                                          msecs_to_jiffies(NDLC_TIMER_T1_WAIT));
 194                                break;
 195                        default:
 196                                kfree_skb(skb);
 197                                break;
 198                        }
 199                } else if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_DATAFRAME) {
 200                        nci_recv_frame(ndlc->ndev, skb);
 201                } else {
 202                        kfree_skb(skb);
 203                }
 204        }
 205}
 206
 207static void llt_ndlc_sm_work(struct work_struct *work)
 208{
 209        struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work);
 210
 211        llt_ndlc_send_queue(ndlc);
 212        llt_ndlc_rcv_queue(ndlc);
 213
 214        if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) {
 215                pr_debug
 216                    ("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n");
 217                ndlc->t1_active = false;
 218
 219                llt_ndlc_requeue_data_pending(ndlc);
 220                llt_ndlc_send_queue(ndlc);
 221        }
 222
 223        if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) {
 224                pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n");
 225                ndlc->t2_active = false;
 226                ndlc->t1_active = false;
 227                del_timer_sync(&ndlc->t1_timer);
 228                del_timer_sync(&ndlc->t2_timer);
 229                ndlc_close(ndlc);
 230                ndlc->hard_fault = -EREMOTEIO;
 231        }
 232}
 233
 234void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb)
 235{
 236        if (skb == NULL) {
 237                pr_err("NULL Frame -> link is dead\n");
 238                ndlc->hard_fault = -EREMOTEIO;
 239                ndlc_close(ndlc);
 240        } else {
 241                NDLC_DUMP_SKB("incoming frame", skb);
 242                skb_queue_tail(&ndlc->rcv_q, skb);
 243        }
 244
 245        schedule_work(&ndlc->sm_work);
 246}
 247EXPORT_SYMBOL(ndlc_recv);
 248
 249static void ndlc_t1_timeout(struct timer_list *t)
 250{
 251        struct llt_ndlc *ndlc = from_timer(ndlc, t, t1_timer);
 252
 253        pr_debug("\n");
 254
 255        schedule_work(&ndlc->sm_work);
 256}
 257
 258static void ndlc_t2_timeout(struct timer_list *t)
 259{
 260        struct llt_ndlc *ndlc = from_timer(ndlc, t, t2_timer);
 261
 262        pr_debug("\n");
 263
 264        schedule_work(&ndlc->sm_work);
 265}
 266
 267int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
 268               int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
 269               struct st_nci_se_status *se_status)
 270{
 271        struct llt_ndlc *ndlc;
 272
 273        ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL);
 274        if (!ndlc)
 275                return -ENOMEM;
 276
 277        ndlc->ops = phy_ops;
 278        ndlc->phy_id = phy_id;
 279        ndlc->dev = dev;
 280        ndlc->powered = 0;
 281
 282        *ndlc_id = ndlc;
 283
 284        /* initialize timers */
 285        timer_setup(&ndlc->t1_timer, ndlc_t1_timeout, 0);
 286        timer_setup(&ndlc->t2_timer, ndlc_t2_timeout, 0);
 287
 288        skb_queue_head_init(&ndlc->rcv_q);
 289        skb_queue_head_init(&ndlc->send_q);
 290        skb_queue_head_init(&ndlc->ack_pending_q);
 291
 292        INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
 293
 294        return st_nci_probe(ndlc, phy_headroom, phy_tailroom, se_status);
 295}
 296EXPORT_SYMBOL(ndlc_probe);
 297
 298void ndlc_remove(struct llt_ndlc *ndlc)
 299{
 300        st_nci_remove(ndlc->ndev);
 301
 302        /* cancel timers */
 303        del_timer_sync(&ndlc->t1_timer);
 304        del_timer_sync(&ndlc->t2_timer);
 305        ndlc->t2_active = false;
 306        ndlc->t1_active = false;
 307
 308        skb_queue_purge(&ndlc->rcv_q);
 309        skb_queue_purge(&ndlc->send_q);
 310}
 311EXPORT_SYMBOL(ndlc_remove);
 312