diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2011-12-14 10:43:11 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-12-14 14:50:13 -0500 |
commit | 361f3cb7f9cfdb82c80926d0e7843c098c034545 (patch) | |
tree | ed61b2e95795fc18cce925bc89eceb2f8a915484 /drivers/nfc | |
parent | 541d920b05b538ec0d9ae8ce619ee4fc6fb19e32 (diff) |
NFC: DEP link hook implementation for pn533
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/pn533.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index dccd96552f5d..b8b6c2abbd4a 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
72 | #define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A | 72 | #define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A |
73 | #define PN533_CMD_IN_ATR 0x50 | 73 | #define PN533_CMD_IN_ATR 0x50 |
74 | #define PN533_CMD_IN_RELEASE 0x52 | 74 | #define PN533_CMD_IN_RELEASE 0x52 |
75 | #define PN533_CMD_IN_JUMP_FOR_DEP 0x56 | ||
75 | 76 | ||
76 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) | 77 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) |
77 | 78 | ||
@@ -231,6 +232,26 @@ struct pn533_cmd_activate_response { | |||
231 | u8 gt[]; | 232 | u8 gt[]; |
232 | } __packed; | 233 | } __packed; |
233 | 234 | ||
235 | /* PN533_CMD_IN_JUMP_FOR_DEP */ | ||
236 | struct pn533_cmd_jump_dep { | ||
237 | u8 active; | ||
238 | u8 baud; | ||
239 | u8 next; | ||
240 | u8 gt[]; | ||
241 | } __packed; | ||
242 | |||
243 | struct pn533_cmd_jump_dep_response { | ||
244 | u8 status; | ||
245 | u8 tg; | ||
246 | u8 nfcid3t[10]; | ||
247 | u8 didt; | ||
248 | u8 bst; | ||
249 | u8 brt; | ||
250 | u8 to; | ||
251 | u8 ppt; | ||
252 | /* optional */ | ||
253 | u8 gt[]; | ||
254 | } __packed; | ||
234 | 255 | ||
235 | struct pn533 { | 256 | struct pn533 { |
236 | struct usb_device *udev; | 257 | struct usb_device *udev; |
@@ -1244,6 +1265,142 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) | |||
1244 | return; | 1265 | return; |
1245 | } | 1266 | } |
1246 | 1267 | ||
1268 | |||
1269 | static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, | ||
1270 | u8 *params, int params_len) | ||
1271 | { | ||
1272 | struct pn533_cmd_jump_dep *cmd; | ||
1273 | struct pn533_cmd_jump_dep_response *resp; | ||
1274 | struct nfc_target nfc_target; | ||
1275 | u8 target_gt_len; | ||
1276 | int rc; | ||
1277 | |||
1278 | if (params_len == -ENOENT) { | ||
1279 | nfc_dev_dbg(&dev->interface->dev, ""); | ||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | if (params_len < 0) { | ||
1284 | nfc_dev_err(&dev->interface->dev, | ||
1285 | "Error %d when bringing DEP link up", | ||
1286 | params_len); | ||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
1290 | if (dev->tgt_available_prots && | ||
1291 | !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) { | ||
1292 | nfc_dev_err(&dev->interface->dev, | ||
1293 | "The target does not support DEP"); | ||
1294 | return -EINVAL; | ||
1295 | } | ||
1296 | |||
1297 | resp = (struct pn533_cmd_jump_dep_response *) params; | ||
1298 | cmd = (struct pn533_cmd_jump_dep *) arg; | ||
1299 | rc = resp->status & PN533_CMD_RET_MASK; | ||
1300 | if (rc != PN533_CMD_RET_SUCCESS) { | ||
1301 | nfc_dev_err(&dev->interface->dev, | ||
1302 | "Bringing DEP link up failed %d", rc); | ||
1303 | return 0; | ||
1304 | } | ||
1305 | |||
1306 | if (!dev->tgt_available_prots) { | ||
1307 | nfc_dev_dbg(&dev->interface->dev, "Creating new target"); | ||
1308 | |||
1309 | nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK; | ||
1310 | rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1); | ||
1311 | if (rc) | ||
1312 | return 0; | ||
1313 | |||
1314 | dev->tgt_available_prots = 0; | ||
1315 | } | ||
1316 | |||
1317 | dev->tgt_active_prot = NFC_PROTO_NFC_DEP; | ||
1318 | |||
1319 | /* ATR_RES general bytes are located at offset 17 */ | ||
1320 | target_gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 17; | ||
1321 | rc = nfc_set_remote_general_bytes(dev->nfc_dev, | ||
1322 | resp->gt, target_gt_len); | ||
1323 | if (rc == 0) | ||
1324 | rc = nfc_dep_link_is_up(dev->nfc_dev, | ||
1325 | dev->nfc_dev->targets[0].idx, | ||
1326 | !cmd->active, NFC_RF_INITIATOR); | ||
1327 | |||
1328 | return 0; | ||
1329 | } | ||
1330 | |||
1331 | static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, | ||
1332 | u8 comm_mode, u8 rf_mode) | ||
1333 | { | ||
1334 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); | ||
1335 | struct pn533_cmd_jump_dep *cmd; | ||
1336 | u8 cmd_len, local_gt_len, *local_gt; | ||
1337 | int rc; | ||
1338 | |||
1339 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
1340 | |||
1341 | if (rf_mode == NFC_RF_TARGET) { | ||
1342 | nfc_dev_err(&dev->interface->dev, "Target mode not supported"); | ||
1343 | return -EOPNOTSUPP; | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | if (dev->poll_mod_count) { | ||
1348 | nfc_dev_err(&dev->interface->dev, | ||
1349 | "Cannot bring the DEP link up while polling"); | ||
1350 | return -EBUSY; | ||
1351 | } | ||
1352 | |||
1353 | if (dev->tgt_active_prot) { | ||
1354 | nfc_dev_err(&dev->interface->dev, | ||
1355 | "There is already an active target"); | ||
1356 | return -EBUSY; | ||
1357 | } | ||
1358 | |||
1359 | local_gt = nfc_get_local_general_bytes(dev->nfc_dev, &local_gt_len); | ||
1360 | if (local_gt_len > NFC_MAX_GT_LEN) | ||
1361 | return -EINVAL; | ||
1362 | |||
1363 | cmd_len = sizeof(struct pn533_cmd_jump_dep) + local_gt_len; | ||
1364 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
1365 | if (cmd == NULL) | ||
1366 | return -ENOMEM; | ||
1367 | |||
1368 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP); | ||
1369 | |||
1370 | cmd->active = !comm_mode; | ||
1371 | cmd->baud = 0; | ||
1372 | if (local_gt != NULL) { | ||
1373 | cmd->next = 4; /* We have some Gi */ | ||
1374 | memcpy(cmd->gt, local_gt, local_gt_len); | ||
1375 | } else { | ||
1376 | cmd->next = 0; | ||
1377 | } | ||
1378 | |||
1379 | memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), cmd, cmd_len); | ||
1380 | dev->out_frame->datalen += cmd_len; | ||
1381 | |||
1382 | pn533_tx_frame_finish(dev->out_frame); | ||
1383 | |||
1384 | rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, | ||
1385 | dev->in_maxlen, pn533_in_dep_link_up_complete, | ||
1386 | cmd, GFP_KERNEL); | ||
1387 | if (rc) | ||
1388 | goto out; | ||
1389 | |||
1390 | |||
1391 | out: | ||
1392 | kfree(cmd); | ||
1393 | |||
1394 | return rc; | ||
1395 | } | ||
1396 | |||
1397 | static int pn533_dep_link_down(struct nfc_dev *nfc_dev) | ||
1398 | { | ||
1399 | pn533_deactivate_target(nfc_dev, 0); | ||
1400 | |||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1247 | #define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) | 1404 | #define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) |
1248 | #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 | 1405 | #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 |
1249 | 1406 | ||
@@ -1439,6 +1596,8 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, | |||
1439 | struct nfc_ops pn533_nfc_ops = { | 1596 | struct nfc_ops pn533_nfc_ops = { |
1440 | .dev_up = NULL, | 1597 | .dev_up = NULL, |
1441 | .dev_down = NULL, | 1598 | .dev_down = NULL, |
1599 | .dep_link_up = pn533_dep_link_up, | ||
1600 | .dep_link_down = pn533_dep_link_down, | ||
1442 | .start_poll = pn533_start_poll, | 1601 | .start_poll = pn533_start_poll, |
1443 | .stop_poll = pn533_stop_poll, | 1602 | .stop_poll = pn533_stop_poll, |
1444 | .activate_target = pn533_activate_target, | 1603 | .activate_target = pn533_activate_target, |