NFC: Introduce target mode tx ops
[deliverable/linux.git] / drivers / nfc / pn533.c
index e6ec16d92e65d2ee362119f3f015f6d9322d00d2..fd94c6f5d6a83558e39a1a4cd37ea002af5c6294 100644 (file)
@@ -74,6 +74,8 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_IN_RELEASE 0x52
 #define PN533_CMD_IN_JUMP_FOR_DEP 0x56
 
+#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
+
 #define PN533_CMD_RESPONSE(cmd) (cmd + 1)
 
 /* PN533 Return codes */
@@ -253,6 +255,29 @@ struct pn533_cmd_jump_dep_response {
        u8 gt[];
 } __packed;
 
+
+/* PN533_TG_INIT_AS_TARGET */
+#define PN533_INIT_TARGET_PASSIVE 0x1
+#define PN533_INIT_TARGET_DEP 0x2
+
+#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3
+#define PN533_INIT_TARGET_RESP_ACTIVE     0x1
+#define PN533_INIT_TARGET_RESP_DEP        0x4
+
+struct pn533_cmd_init_target {
+       u8 mode;
+       u8 mifare[6];
+       u8 felica[18];
+       u8 nfcid3[10];
+       u8 gb_len;
+       u8 gb[];
+} __packed;
+
+struct pn533_cmd_init_target_response {
+       u8 mode;
+       u8 cmd[];
+} __packed;
+
 struct pn533 {
        struct usb_device *udev;
        struct usb_interface *interface;
@@ -394,9 +419,6 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
        struct pn533_frame *in_frame;
        int rc;
 
-       if (dev == NULL)
-               return;
-
        in_frame = dev->wq_in_frame;
 
        if (dev->wq_in_error)
@@ -1081,14 +1103,112 @@ stop_poll:
        return 0;
 }
 
-static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static int pn533_init_target_frame(struct pn533_frame *frame,
+                                  u8 *gb, size_t gb_len)
+{
+       struct pn533_cmd_init_target *cmd;
+       size_t cmd_len;
+
+       cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
+       cmd = kzalloc(cmd_len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+
+       /* DEP support only */
+       cmd->mode |= PN533_INIT_TARGET_DEP;
+       get_random_bytes(cmd->nfcid3, 10);
+       cmd->gb_len = gb_len;
+       memcpy(cmd->gb, gb, gb_len);
+       /* Len Tk */
+       cmd->gb[gb_len] = 0;
+
+       memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+       frame->datalen += cmd_len;
+
+       pn533_tx_frame_finish(frame);
+
+       return 0;
+}
+
+#define ATR_REQ_GB_OFFSET 17
+static int pn533_init_target_complete(struct pn533 *dev, void *arg,
+                                     u8 *params, int params_len)
+{
+       struct pn533_cmd_init_target_response *resp;
+       u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+       size_t gb_len;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       if (params_len < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when starting as a target",
+                           params_len);
+
+               return params_len;
+       }
+
+       if (params_len < ATR_REQ_GB_OFFSET + 1)
+               return -EINVAL;
+
+       resp = (struct pn533_cmd_init_target_response *) params;
+
+       nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
+                   resp->mode, params_len);
+
+       frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
+       if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+               comm_mode = NFC_COMM_ACTIVE;
+
+       /* Again, only DEP */
+       if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+               return -EOPNOTSUPP;
+
+       gb = resp->cmd + ATR_REQ_GB_OFFSET;
+       gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+
+       return nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+                               comm_mode, gb, gb_len);
+}
+
+static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_poll_modulations *start_mod;
+       u8 *gb;
+       size_t gb_len;
        int rc;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
-                                                               protocols);
+       pn533_poll_reset_mod_list(dev);
+
+       gb = nfc_get_local_general_bytes(nfc_dev, &gb_len);
+       if (gb == NULL)
+               return -ENOMEM;
+
+       rc = pn533_init_target_frame(dev->out_frame, gb, gb_len);
+       if (rc < 0)
+               return rc;
+
+       rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+                                       dev->in_maxlen,
+                                       pn533_init_target_complete,
+                                       NULL, GFP_KERNEL);
+
+       if (rc)
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when trying to initiate as a target", rc);
+
+       dev->poll_mod_count++;
+
+       return rc;
+}
+
+static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols)
+{
+       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+       struct pn533_poll_modulations *start_mod;
+       int rc;
 
        if (dev->poll_mod_count) {
                nfc_dev_err(&dev->interface->dev, "Polling operation already"
@@ -1096,12 +1216,6 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
                return -EBUSY;
        }
 
-       if (dev->tgt_active_prot) {
-               nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
-                                                       " already activated");
-               return -EBUSY;
-       }
-
        pn533_poll_create_mod_list(dev, protocols);
 
        if (!dev->poll_mod_count) {
@@ -1138,6 +1252,30 @@ error:
        return rc;
 }
 
+static int pn533_start_poll(struct nfc_dev *nfc_dev,
+                           u32 im_protocols, u32 tm_protocols)
+{
+       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dev_dbg(&dev->interface->dev,
+                   "%s: im protocols 0x%x tm protocols 0x%x",
+                   __func__, im_protocols, tm_protocols);
+
+       if (dev->tgt_active_prot) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Cannot poll with a target already activated");
+               return -EBUSY;
+       }
+
+       if (im_protocols)
+               return pn533_start_im_poll(nfc_dev, im_protocols);
+
+       if (tm_protocols)
+               return pn533_init_target(nfc_dev, tm_protocols);
+
+       return -EINVAL;
+}
+
 static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
@@ -1194,8 +1332,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
        return rc;
 }
 
-static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
-                                                               u32 protocol)
+static int pn533_activate_target(struct nfc_dev *nfc_dev,
+                                struct nfc_target *target, u32 protocol)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        int rc;
@@ -1243,7 +1381,8 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
        return 0;
 }
 
-static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
+                                   struct nfc_target *target)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        u8 tg;
@@ -1351,7 +1490,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
        return 0;
 }
 
-static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx,
+static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
                             u8 comm_mode, u8* gb, size_t gb_len)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
@@ -1552,10 +1691,9 @@ error:
        return 0;
 }
 
-static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
-                                               struct sk_buff *skb,
-                                               data_exchange_cb_t cb,
-                                               void *cb_context)
+static int pn533_transceive(struct nfc_dev *nfc_dev,
+                           struct nfc_target *target, struct sk_buff *skb,
+                           data_exchange_cb_t cb, void *cb_context)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        struct pn533_frame *out_frame, *in_frame;
@@ -1715,7 +1853,7 @@ struct nfc_ops pn533_nfc_ops = {
        .stop_poll = pn533_stop_poll,
        .activate_target = pn533_activate_target,
        .deactivate_target = pn533_deactivate_target,
-       .data_exchange = pn533_data_exchange,
+       .im_transceive = pn533_transceive,
 };
 
 static int pn533_probe(struct usb_interface *interface,
This page took 0.04682 seconds and 5 git commands to generate.