diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2012-05-30 17:54:55 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-06-04 15:34:29 -0400 |
commit | ad3823cef650bdc1ca9e7bf1a01b87ad3c0425de (patch) | |
tree | ee616628813e0fe244afb55e568a769203cc4c0a /drivers/nfc/pn533.c | |
parent | fe7c580073280c15bb4eb4f82bf20dddc1a68383 (diff) |
NFC: Implement pn533 target mode polling loop
We only want to support p2p target mode for now, no host card emulation.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc/pn533.c')
-rw-r--r-- | drivers/nfc/pn533.c | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 38a523c62132..605a08a62e45 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -74,6 +74,8 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
74 | #define PN533_CMD_IN_RELEASE 0x52 | 74 | #define PN533_CMD_IN_RELEASE 0x52 |
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 | ||
78 | |||
77 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) | 79 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) |
78 | 80 | ||
79 | /* PN533 Return codes */ | 81 | /* PN533 Return codes */ |
@@ -253,6 +255,25 @@ struct pn533_cmd_jump_dep_response { | |||
253 | u8 gt[]; | 255 | u8 gt[]; |
254 | } __packed; | 256 | } __packed; |
255 | 257 | ||
258 | |||
259 | /* PN533_TG_INIT_AS_TARGET */ | ||
260 | #define PN533_INIT_TARGET_PASSIVE 0x1 | ||
261 | #define PN533_INIT_TARGET_DEP 0x2 | ||
262 | |||
263 | struct pn533_cmd_init_target { | ||
264 | u8 mode; | ||
265 | u8 mifare[6]; | ||
266 | u8 felica[18]; | ||
267 | u8 nfcid3[10]; | ||
268 | u8 gb_len; | ||
269 | u8 gb[]; | ||
270 | } __packed; | ||
271 | |||
272 | struct pn533_cmd_init_target_response { | ||
273 | u8 mode; | ||
274 | u8 cmd[]; | ||
275 | } __packed; | ||
276 | |||
256 | struct pn533 { | 277 | struct pn533 { |
257 | struct usb_device *udev; | 278 | struct usb_device *udev; |
258 | struct usb_interface *interface; | 279 | struct usb_interface *interface; |
@@ -1078,11 +1099,88 @@ stop_poll: | |||
1078 | return 0; | 1099 | return 0; |
1079 | } | 1100 | } |
1080 | 1101 | ||
1081 | static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols) | 1102 | static int pn533_init_target_frame(struct pn533_frame *frame, |
1103 | u8 *gb, size_t gb_len) | ||
1082 | { | 1104 | { |
1105 | struct pn533_cmd_init_target *cmd; | ||
1106 | size_t cmd_len; | ||
1107 | |||
1108 | cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1; | ||
1109 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
1110 | if (cmd == NULL) | ||
1111 | return -ENOMEM; | ||
1112 | |||
1113 | pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET); | ||
1114 | |||
1115 | /* DEP support only */ | ||
1116 | cmd->mode |= PN533_INIT_TARGET_DEP; | ||
1117 | get_random_bytes(cmd->nfcid3, 10); | ||
1118 | cmd->gb_len = gb_len; | ||
1119 | memcpy(cmd->gb, gb, gb_len); | ||
1120 | /* Len Tk */ | ||
1121 | cmd->gb[gb_len] = 0; | ||
1122 | |||
1123 | memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len); | ||
1124 | frame->datalen += cmd_len; | ||
1125 | |||
1126 | pn533_tx_frame_finish(frame); | ||
1127 | |||
1083 | return 0; | 1128 | return 0; |
1084 | } | 1129 | } |
1085 | 1130 | ||
1131 | static int pn533_init_target_complete(struct pn533 *dev, void *arg, | ||
1132 | u8 *params, int params_len) | ||
1133 | { | ||
1134 | struct pn533_cmd_init_target_response *resp; | ||
1135 | |||
1136 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
1137 | |||
1138 | if (params_len < 0) { | ||
1139 | nfc_dev_err(&dev->interface->dev, | ||
1140 | "Error %d when starting as a target", | ||
1141 | params_len); | ||
1142 | |||
1143 | return params_len; | ||
1144 | } | ||
1145 | |||
1146 | resp = (struct pn533_cmd_init_target_response *) params; | ||
1147 | |||
1148 | nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x\n", resp->mode); | ||
1149 | |||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols) | ||
1154 | { | ||
1155 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); | ||
1156 | u8 *gb; | ||
1157 | size_t gb_len; | ||
1158 | int rc; | ||
1159 | |||
1160 | pn533_poll_reset_mod_list(dev); | ||
1161 | |||
1162 | gb = nfc_get_local_general_bytes(nfc_dev, &gb_len); | ||
1163 | if (gb == NULL) | ||
1164 | return -ENOMEM; | ||
1165 | |||
1166 | rc = pn533_init_target_frame(dev->out_frame, gb, gb_len); | ||
1167 | if (rc < 0) | ||
1168 | return rc; | ||
1169 | |||
1170 | rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, | ||
1171 | dev->in_maxlen, | ||
1172 | pn533_init_target_complete, | ||
1173 | NULL, GFP_KERNEL); | ||
1174 | |||
1175 | if (rc) | ||
1176 | nfc_dev_err(&dev->interface->dev, | ||
1177 | "Error %d when trying to initiate as a target", rc); | ||
1178 | |||
1179 | dev->poll_mod_count++; | ||
1180 | |||
1181 | return rc; | ||
1182 | } | ||
1183 | |||
1086 | static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols) | 1184 | static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols) |
1087 | { | 1185 | { |
1088 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); | 1186 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); |
@@ -1146,12 +1244,13 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, | |||
1146 | return -EBUSY; | 1244 | return -EBUSY; |
1147 | } | 1245 | } |
1148 | 1246 | ||
1149 | if (!tm_protocols) | 1247 | if (im_protocols) |
1150 | return pn533_start_im_poll(nfc_dev, im_protocols); | 1248 | return pn533_start_im_poll(nfc_dev, im_protocols); |
1151 | else if (!im_protocols) | 1249 | |
1250 | if (tm_protocols) | ||
1152 | return pn533_init_target(nfc_dev, tm_protocols); | 1251 | return pn533_init_target(nfc_dev, tm_protocols); |
1153 | else | 1252 | |
1154 | return -EINVAL; | 1253 | return -EINVAL; |
1155 | } | 1254 | } |
1156 | 1255 | ||
1157 | static void pn533_stop_poll(struct nfc_dev *nfc_dev) | 1256 | static void pn533_stop_poll(struct nfc_dev *nfc_dev) |