diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2012-05-30 18:07:51 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-06-04 15:34:31 -0400 |
commit | 103b34cf5fe2bb72c38afa8523dd206e6ef3b5fe (patch) | |
tree | c0c6268d9089cdc679c7873bd12ca70fbb237e39 /drivers/nfc | |
parent | 73167ced31d15c04e57b9e0885ac05675e9195a4 (diff) |
NFC: Implement the pn533 target mode data fetching routine
This one needs to be called as soon as we are activated as a target, for
the pn533 to receive the first SYMM and keep the LLCP link alive.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/pn533.c | 85 |
1 files changed, 80 insertions, 5 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index fd94c6f5d6a8..6a506e267d20 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -75,6 +75,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
75 | #define PN533_CMD_IN_JUMP_FOR_DEP 0x56 | 75 | #define PN533_CMD_IN_JUMP_FOR_DEP 0x56 |
76 | 76 | ||
77 | #define PN533_CMD_TG_INIT_AS_TARGET 0x8c | 77 | #define PN533_CMD_TG_INIT_AS_TARGET 0x8c |
78 | #define PN533_CMD_TG_GET_DATA 0x86 | ||
78 | 79 | ||
79 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) | 80 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) |
80 | 81 | ||
@@ -83,6 +84,9 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
83 | #define PN533_CMD_MI_MASK 0x40 | 84 | #define PN533_CMD_MI_MASK 0x40 |
84 | #define PN533_CMD_RET_SUCCESS 0x00 | 85 | #define PN533_CMD_RET_SUCCESS 0x00 |
85 | 86 | ||
87 | /* PN533 status codes */ | ||
88 | #define PN533_STATUS_TARGET_RELEASED 0x29 | ||
89 | |||
86 | struct pn533; | 90 | struct pn533; |
87 | 91 | ||
88 | typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, | 92 | typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, |
@@ -296,6 +300,7 @@ struct pn533 { | |||
296 | struct workqueue_struct *wq; | 300 | struct workqueue_struct *wq; |
297 | struct work_struct cmd_work; | 301 | struct work_struct cmd_work; |
298 | struct work_struct mi_work; | 302 | struct work_struct mi_work; |
303 | struct work_struct tg_work; | ||
299 | struct pn533_frame *wq_in_frame; | 304 | struct pn533_frame *wq_in_frame; |
300 | int wq_in_error; | 305 | int wq_in_error; |
301 | 306 | ||
@@ -1132,6 +1137,68 @@ static int pn533_init_target_frame(struct pn533_frame *frame, | |||
1132 | return 0; | 1137 | return 0; |
1133 | } | 1138 | } |
1134 | 1139 | ||
1140 | #define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) | ||
1141 | #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 | ||
1142 | static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg, | ||
1143 | u8 *params, int params_len) | ||
1144 | { | ||
1145 | struct sk_buff *skb_resp = arg; | ||
1146 | struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; | ||
1147 | |||
1148 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
1149 | |||
1150 | if (params_len < 0) { | ||
1151 | nfc_dev_err(&dev->interface->dev, | ||
1152 | "Error %d when starting as a target", | ||
1153 | params_len); | ||
1154 | |||
1155 | return params_len; | ||
1156 | } | ||
1157 | |||
1158 | if (params_len > 0 && params[0] != 0) { | ||
1159 | nfc_tm_deactivated(dev->nfc_dev); | ||
1160 | |||
1161 | kfree_skb(skb_resp); | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); | ||
1166 | skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); | ||
1167 | skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); | ||
1168 | |||
1169 | return nfc_tm_data_received(dev->nfc_dev, skb_resp); | ||
1170 | } | ||
1171 | |||
1172 | static void pn533_wq_tg_get_data(struct work_struct *work) | ||
1173 | { | ||
1174 | struct pn533 *dev = container_of(work, struct pn533, tg_work); | ||
1175 | struct pn533_frame *in_frame; | ||
1176 | struct sk_buff *skb_resp; | ||
1177 | size_t skb_resp_len; | ||
1178 | |||
1179 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
1180 | |||
1181 | skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN + | ||
1182 | PN533_CMD_DATAEXCH_DATA_MAXLEN + | ||
1183 | PN533_FRAME_TAIL_SIZE; | ||
1184 | |||
1185 | skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL); | ||
1186 | if (!skb_resp) | ||
1187 | return; | ||
1188 | |||
1189 | in_frame = (struct pn533_frame *)skb_resp->data; | ||
1190 | |||
1191 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA); | ||
1192 | pn533_tx_frame_finish(dev->out_frame); | ||
1193 | |||
1194 | pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame, | ||
1195 | skb_resp_len, | ||
1196 | pn533_tm_get_data_complete, | ||
1197 | skb_resp, GFP_KERNEL); | ||
1198 | |||
1199 | return; | ||
1200 | } | ||
1201 | |||
1135 | #define ATR_REQ_GB_OFFSET 17 | 1202 | #define ATR_REQ_GB_OFFSET 17 |
1136 | static int pn533_init_target_complete(struct pn533 *dev, void *arg, | 1203 | static int pn533_init_target_complete(struct pn533 *dev, void *arg, |
1137 | u8 *params, int params_len) | 1204 | u8 *params, int params_len) |
@@ -1139,6 +1206,7 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg, | |||
1139 | struct pn533_cmd_init_target_response *resp; | 1206 | struct pn533_cmd_init_target_response *resp; |
1140 | u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb; | 1207 | u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb; |
1141 | size_t gb_len; | 1208 | size_t gb_len; |
1209 | int rc; | ||
1142 | 1210 | ||
1143 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 1211 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
1144 | 1212 | ||
@@ -1169,8 +1237,17 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg, | |||
1169 | gb = resp->cmd + ATR_REQ_GB_OFFSET; | 1237 | gb = resp->cmd + ATR_REQ_GB_OFFSET; |
1170 | gb_len = params_len - (ATR_REQ_GB_OFFSET + 1); | 1238 | gb_len = params_len - (ATR_REQ_GB_OFFSET + 1); |
1171 | 1239 | ||
1172 | return nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, | 1240 | rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, |
1173 | comm_mode, gb, gb_len); | 1241 | comm_mode, gb, gb_len); |
1242 | if (rc < 0) { | ||
1243 | nfc_dev_err(&dev->interface->dev, | ||
1244 | "Error when signaling target activation"); | ||
1245 | return rc; | ||
1246 | } | ||
1247 | |||
1248 | queue_work(dev->wq, &dev->tg_work); | ||
1249 | |||
1250 | return 0; | ||
1174 | } | 1251 | } |
1175 | 1252 | ||
1176 | static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols) | 1253 | static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols) |
@@ -1553,9 +1630,6 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev) | |||
1553 | return 0; | 1630 | return 0; |
1554 | } | 1631 | } |
1555 | 1632 | ||
1556 | #define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) | ||
1557 | #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 | ||
1558 | |||
1559 | static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb) | 1633 | static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb) |
1560 | { | 1634 | { |
1561 | int payload_len = skb->len; | 1635 | int payload_len = skb->len; |
@@ -1920,6 +1994,7 @@ static int pn533_probe(struct usb_interface *interface, | |||
1920 | 1994 | ||
1921 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); | 1995 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); |
1922 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); | 1996 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); |
1997 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); | ||
1923 | dev->wq = alloc_workqueue("pn533", | 1998 | dev->wq = alloc_workqueue("pn533", |
1924 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | 1999 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, |
1925 | 1); | 2000 | 1); |