diff options
author | Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> | 2012-12-10 08:42:46 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-01-09 18:51:36 -0500 |
commit | b1e666f503b5479efe9adf79fb46f09fe4f04af5 (patch) | |
tree | fa92b74d9d48a011277205e81e533e1d6a9cd585 /drivers/nfc | |
parent | 13003649b1ebb4ea51341a9405a2ec5b10cf4f7e (diff) |
NFC: pn533: Del frame logic from Data Exchange cmd
Remove frame logic from transceive cb using new iface
for async send.
For pn533_wq_mi_recv() use pn533_send_cmd_direct_async which
sends the cmd directly to the hardware, skipping cmd queue.
Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/pn533.c | 309 |
1 files changed, 141 insertions, 168 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index aa7803f16773..91e1594dfd13 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -360,6 +360,7 @@ struct pn533 { | |||
360 | 360 | ||
361 | pn533_cmd_complete_t cmd_complete; | 361 | pn533_cmd_complete_t cmd_complete; |
362 | void *cmd_complete_arg; | 362 | void *cmd_complete_arg; |
363 | void *cmd_complete_mi_arg; | ||
363 | struct mutex cmd_lock; | 364 | struct mutex cmd_lock; |
364 | u8 cmd; | 365 | u8 cmd; |
365 | 366 | ||
@@ -848,6 +849,57 @@ static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code, | |||
848 | return rc; | 849 | return rc; |
849 | } | 850 | } |
850 | 851 | ||
852 | /* | ||
853 | * pn533_send_cmd_direct_async | ||
854 | * | ||
855 | * The function sends a piority cmd directly to the chip omiting the cmd | ||
856 | * queue. It's intended to be used by chaining mechanism of received responses | ||
857 | * where the host has to request every single chunk of data before scheduling | ||
858 | * next cmd from the queue. | ||
859 | */ | ||
860 | static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, | ||
861 | struct sk_buff *req, | ||
862 | pn533_send_async_complete_t complete_cb, | ||
863 | void *complete_cb_context) | ||
864 | { | ||
865 | struct pn533_send_async_complete_arg *arg; | ||
866 | struct sk_buff *resp; | ||
867 | int rc; | ||
868 | int resp_len = PN533_FRAME_HEADER_LEN + | ||
869 | PN533_FRAME_MAX_PAYLOAD_LEN + | ||
870 | PN533_FRAME_TAIL_LEN; | ||
871 | |||
872 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
873 | |||
874 | resp = alloc_skb(resp_len, GFP_KERNEL); | ||
875 | if (!resp) | ||
876 | return -ENOMEM; | ||
877 | |||
878 | arg = kzalloc(sizeof(arg), GFP_KERNEL); | ||
879 | if (!arg) { | ||
880 | dev_kfree_skb(resp); | ||
881 | return -ENOMEM; | ||
882 | } | ||
883 | |||
884 | arg->complete_cb = complete_cb; | ||
885 | arg->complete_cb_context = complete_cb_context; | ||
886 | arg->resp = resp; | ||
887 | arg->req = req; | ||
888 | |||
889 | pn533_build_cmd_frame(cmd_code, req); | ||
890 | |||
891 | rc = __pn533_send_cmd_frame_async(dev, (struct pn533_frame *)req->data, | ||
892 | (struct pn533_frame *)resp->data, | ||
893 | resp_len, pn533_send_async_complete, | ||
894 | arg); | ||
895 | if (rc < 0) { | ||
896 | dev_kfree_skb(resp); | ||
897 | kfree(arg); | ||
898 | } | ||
899 | |||
900 | return rc; | ||
901 | } | ||
902 | |||
851 | static void pn533_wq_cmd(struct work_struct *work) | 903 | static void pn533_wq_cmd(struct work_struct *work) |
852 | { | 904 | { |
853 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); | 905 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); |
@@ -2024,69 +2076,7 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev) | |||
2024 | return 0; | 2076 | return 0; |
2025 | } | 2077 | } |
2026 | 2078 | ||
2027 | static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb, | ||
2028 | bool target) | ||
2029 | { | ||
2030 | int payload_len = skb->len; | ||
2031 | struct pn533_frame *out_frame; | ||
2032 | u8 tg; | ||
2033 | |||
2034 | nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__, | ||
2035 | payload_len); | ||
2036 | |||
2037 | if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { | ||
2038 | /* TODO: Implement support to multi-part data exchange */ | ||
2039 | nfc_dev_err(&dev->interface->dev, "Data length greater than the" | ||
2040 | " max allowed: %d", | ||
2041 | PN533_CMD_DATAEXCH_DATA_MAXLEN); | ||
2042 | return -ENOSYS; | ||
2043 | } | ||
2044 | |||
2045 | skb_push(skb, PN533_FRAME_HEADER_LEN); | ||
2046 | |||
2047 | if (target == true) { | ||
2048 | switch (dev->device_type) { | ||
2049 | case PN533_DEVICE_PASORI: | ||
2050 | if (dev->tgt_active_prot == NFC_PROTO_FELICA) { | ||
2051 | out_frame = (struct pn533_frame *) skb->data; | ||
2052 | pn533_tx_frame_init(out_frame, | ||
2053 | PN533_CMD_IN_COMM_THRU); | ||
2054 | |||
2055 | break; | ||
2056 | } | ||
2057 | |||
2058 | default: | ||
2059 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); | ||
2060 | out_frame = (struct pn533_frame *) skb->data; | ||
2061 | pn533_tx_frame_init(out_frame, | ||
2062 | PN533_CMD_IN_DATA_EXCHANGE); | ||
2063 | tg = 1; | ||
2064 | memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), | ||
2065 | &tg, sizeof(u8)); | ||
2066 | out_frame->datalen += sizeof(u8); | ||
2067 | |||
2068 | break; | ||
2069 | } | ||
2070 | |||
2071 | } else { | ||
2072 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); | ||
2073 | out_frame = (struct pn533_frame *) skb->data; | ||
2074 | pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA); | ||
2075 | } | ||
2076 | |||
2077 | |||
2078 | /* The data is already in the out_frame, just update the datalen */ | ||
2079 | out_frame->datalen += payload_len; | ||
2080 | |||
2081 | pn533_tx_frame_finish(out_frame); | ||
2082 | skb_put(skb, PN533_FRAME_TAIL_LEN); | ||
2083 | |||
2084 | return 0; | ||
2085 | } | ||
2086 | |||
2087 | struct pn533_data_exchange_arg { | 2079 | struct pn533_data_exchange_arg { |
2088 | struct sk_buff *skb_resp; | ||
2089 | struct sk_buff *skb_out; | ||
2090 | data_exchange_cb_t cb; | 2080 | data_exchange_cb_t cb; |
2091 | void *cb_context; | 2081 | void *cb_context; |
2092 | }; | 2082 | }; |
@@ -2130,47 +2120,44 @@ out: | |||
2130 | } | 2120 | } |
2131 | 2121 | ||
2132 | static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, | 2122 | static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, |
2133 | u8 *params, int params_len) | 2123 | struct sk_buff *resp) |
2134 | { | 2124 | { |
2135 | struct pn533_data_exchange_arg *arg = _arg; | 2125 | struct pn533_data_exchange_arg *arg = _arg; |
2136 | struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp; | 2126 | struct sk_buff *skb; |
2137 | struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; | 2127 | int rc = 0; |
2138 | int err = 0; | 2128 | u8 status, ret, mi; |
2139 | u8 status; | ||
2140 | u8 cmd_ret; | ||
2141 | 2129 | ||
2142 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 2130 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
2143 | 2131 | ||
2144 | dev_kfree_skb(arg->skb_out); | 2132 | if (IS_ERR(resp)) { |
2145 | 2133 | rc = PTR_ERR(resp); | |
2146 | if (params_len < 0) { /* error */ | 2134 | goto _error; |
2147 | err = params_len; | ||
2148 | goto error; | ||
2149 | } | 2135 | } |
2150 | 2136 | ||
2151 | status = params[0]; | 2137 | status = resp->data[0]; |
2138 | ret = status & PN533_CMD_RET_MASK; | ||
2139 | mi = status & PN533_CMD_MI_MASK; | ||
2140 | |||
2141 | skb_pull(resp, sizeof(status)); | ||
2152 | 2142 | ||
2153 | cmd_ret = status & PN533_CMD_RET_MASK; | 2143 | if (ret != PN533_CMD_RET_SUCCESS) { |
2154 | if (cmd_ret != PN533_CMD_RET_SUCCESS) { | 2144 | nfc_dev_err(&dev->interface->dev, |
2155 | nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when" | 2145 | "PN533 reported error %d when exchanging data", |
2156 | " exchanging data", cmd_ret); | 2146 | ret); |
2157 | err = -EIO; | 2147 | rc = -EIO; |
2158 | goto error; | 2148 | goto error; |
2159 | } | 2149 | } |
2160 | 2150 | ||
2161 | skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); | 2151 | skb_queue_tail(&dev->resp_q, resp); |
2162 | skb_pull(skb_resp, PN533_FRAME_HEADER_LEN); | ||
2163 | skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); | ||
2164 | skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_LEN); | ||
2165 | skb_queue_tail(&dev->resp_q, skb_resp); | ||
2166 | 2152 | ||
2167 | if (status & PN533_CMD_MI_MASK) { | 2153 | if (mi) { |
2154 | dev->cmd_complete_mi_arg = arg; | ||
2168 | queue_work(dev->wq, &dev->mi_work); | 2155 | queue_work(dev->wq, &dev->mi_work); |
2169 | return -EINPROGRESS; | 2156 | return -EINPROGRESS; |
2170 | } | 2157 | } |
2171 | 2158 | ||
2172 | skb = pn533_build_response(dev); | 2159 | skb = pn533_build_response(dev); |
2173 | if (skb == NULL) | 2160 | if (!skb) |
2174 | goto error; | 2161 | goto error; |
2175 | 2162 | ||
2176 | arg->cb(arg->cb_context, skb, 0); | 2163 | arg->cb(arg->cb_context, skb, 0); |
@@ -2178,11 +2165,12 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, | |||
2178 | return 0; | 2165 | return 0; |
2179 | 2166 | ||
2180 | error: | 2167 | error: |
2168 | dev_kfree_skb(resp); | ||
2169 | _error: | ||
2181 | skb_queue_purge(&dev->resp_q); | 2170 | skb_queue_purge(&dev->resp_q); |
2182 | dev_kfree_skb(skb_resp); | 2171 | arg->cb(arg->cb_context, NULL, rc); |
2183 | arg->cb(arg->cb_context, NULL, err); | ||
2184 | kfree(arg); | 2172 | kfree(arg); |
2185 | return 0; | 2173 | return rc; |
2186 | } | 2174 | } |
2187 | 2175 | ||
2188 | static int pn533_transceive(struct nfc_dev *nfc_dev, | 2176 | static int pn533_transceive(struct nfc_dev *nfc_dev, |
@@ -2190,14 +2178,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, | |||
2190 | data_exchange_cb_t cb, void *cb_context) | 2178 | data_exchange_cb_t cb, void *cb_context) |
2191 | { | 2179 | { |
2192 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); | 2180 | struct pn533 *dev = nfc_get_drvdata(nfc_dev); |
2193 | struct pn533_frame *out_frame, *in_frame; | 2181 | struct pn533_data_exchange_arg *arg = NULL; |
2194 | struct pn533_data_exchange_arg *arg; | ||
2195 | struct sk_buff *skb_resp; | ||
2196 | int skb_resp_len; | ||
2197 | int rc; | 2182 | int rc; |
2198 | 2183 | ||
2199 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 2184 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
2200 | 2185 | ||
2186 | if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { | ||
2187 | /* TODO: Implement support to multi-part data exchange */ | ||
2188 | nfc_dev_err(&dev->interface->dev, | ||
2189 | "Data length greater than the max allowed: %d", | ||
2190 | PN533_CMD_DATAEXCH_DATA_MAXLEN); | ||
2191 | rc = -ENOSYS; | ||
2192 | goto error; | ||
2193 | } | ||
2194 | |||
2201 | if (!dev->tgt_active_prot) { | 2195 | if (!dev->tgt_active_prot) { |
2202 | nfc_dev_err(&dev->interface->dev, "Cannot exchange data if" | 2196 | nfc_dev_err(&dev->interface->dev, "Cannot exchange data if" |
2203 | " there is no active target"); | 2197 | " there is no active target"); |
@@ -2205,51 +2199,43 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, | |||
2205 | goto error; | 2199 | goto error; |
2206 | } | 2200 | } |
2207 | 2201 | ||
2208 | rc = pn533_build_tx_frame(dev, skb, true); | 2202 | arg = kmalloc(sizeof(*arg), GFP_KERNEL); |
2209 | if (rc) | ||
2210 | goto error; | ||
2211 | |||
2212 | skb_resp_len = PN533_FRAME_HEADER_LEN + | ||
2213 | PN533_CMD_DATAEXCH_HEAD_LEN + | ||
2214 | PN533_CMD_DATAEXCH_DATA_MAXLEN + | ||
2215 | PN533_FRAME_TAIL_LEN; | ||
2216 | |||
2217 | skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL); | ||
2218 | if (!skb_resp) { | ||
2219 | rc = -ENOMEM; | ||
2220 | goto error; | ||
2221 | } | ||
2222 | |||
2223 | in_frame = (struct pn533_frame *) skb_resp->data; | ||
2224 | out_frame = (struct pn533_frame *) skb->data; | ||
2225 | |||
2226 | arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL); | ||
2227 | if (!arg) { | 2203 | if (!arg) { |
2228 | rc = -ENOMEM; | 2204 | rc = -ENOMEM; |
2229 | goto free_skb_resp; | 2205 | goto error; |
2230 | } | 2206 | } |
2231 | 2207 | ||
2232 | arg->skb_resp = skb_resp; | ||
2233 | arg->skb_out = skb; | ||
2234 | arg->cb = cb; | 2208 | arg->cb = cb; |
2235 | arg->cb_context = cb_context; | 2209 | arg->cb_context = cb_context; |
2236 | 2210 | ||
2237 | rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len, | 2211 | switch (dev->device_type) { |
2238 | pn533_data_exchange_complete, arg); | 2212 | case PN533_DEVICE_PASORI: |
2239 | if (rc) { | 2213 | if (dev->tgt_active_prot == NFC_PROTO_FELICA) { |
2240 | nfc_dev_err(&dev->interface->dev, "Error %d when trying to" | 2214 | rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU, |
2241 | " perform data_exchange", rc); | 2215 | skb, |
2242 | goto free_arg; | 2216 | pn533_data_exchange_complete, |
2217 | arg); | ||
2218 | |||
2219 | break; | ||
2220 | } | ||
2221 | default: | ||
2222 | *skb_push(skb, sizeof(u8)) = 1; /*TG*/ | ||
2223 | |||
2224 | rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, | ||
2225 | skb, pn533_data_exchange_complete, | ||
2226 | arg); | ||
2227 | |||
2228 | break; | ||
2243 | } | 2229 | } |
2244 | 2230 | ||
2231 | if (rc < 0) /* rc from send_async */ | ||
2232 | goto error; | ||
2233 | |||
2245 | return 0; | 2234 | return 0; |
2246 | 2235 | ||
2247 | free_arg: | ||
2248 | kfree(arg); | ||
2249 | free_skb_resp: | ||
2250 | kfree_skb(skb_resp); | ||
2251 | error: | 2236 | error: |
2252 | kfree_skb(skb); | 2237 | kfree(arg); |
2238 | dev_kfree_skb(skb); | ||
2253 | return rc; | 2239 | return rc; |
2254 | } | 2240 | } |
2255 | 2241 | ||
@@ -2305,63 +2291,50 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) | |||
2305 | static void pn533_wq_mi_recv(struct work_struct *work) | 2291 | static void pn533_wq_mi_recv(struct work_struct *work) |
2306 | { | 2292 | { |
2307 | struct pn533 *dev = container_of(work, struct pn533, mi_work); | 2293 | struct pn533 *dev = container_of(work, struct pn533, mi_work); |
2308 | struct sk_buff *skb_cmd; | 2294 | |
2309 | struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg; | 2295 | struct sk_buff *skb; |
2310 | struct pn533_frame *out_frame, *in_frame; | ||
2311 | struct sk_buff *skb_resp; | ||
2312 | int skb_resp_len; | ||
2313 | int rc; | 2296 | int rc; |
2314 | 2297 | ||
2315 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 2298 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
2316 | 2299 | ||
2317 | /* This is a zero payload size skb */ | 2300 | skb = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN); |
2318 | skb_cmd = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN); | 2301 | if (!skb) |
2319 | if (skb_cmd == NULL) | 2302 | goto error; |
2320 | goto error_cmd; | ||
2321 | 2303 | ||
2322 | skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN); | 2304 | switch (dev->device_type) { |
2305 | case PN533_DEVICE_PASORI: | ||
2306 | if (dev->tgt_active_prot == NFC_PROTO_FELICA) { | ||
2307 | rc = pn533_send_cmd_direct_async(dev, | ||
2308 | PN533_CMD_IN_COMM_THRU, | ||
2309 | skb, | ||
2310 | pn533_data_exchange_complete, | ||
2311 | dev->cmd_complete_mi_arg); | ||
2323 | 2312 | ||
2324 | rc = pn533_build_tx_frame(dev, skb_cmd, true); | 2313 | break; |
2325 | if (rc) | 2314 | } |
2326 | goto error_frame; | 2315 | default: |
2316 | *skb_put(skb, sizeof(u8)) = 1; /*TG*/ | ||
2327 | 2317 | ||
2328 | skb_resp_len = PN533_FRAME_HEADER_LEN + | 2318 | rc = pn533_send_cmd_direct_async(dev, |
2329 | PN533_CMD_DATAEXCH_HEAD_LEN + | 2319 | PN533_CMD_IN_DATA_EXCHANGE, |
2330 | PN533_CMD_DATAEXCH_DATA_MAXLEN + | 2320 | skb, |
2331 | PN533_FRAME_TAIL_LEN; | 2321 | pn533_data_exchange_complete, |
2322 | dev->cmd_complete_mi_arg); | ||
2332 | 2323 | ||
2333 | skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL); | 2324 | break; |
2334 | if (!skb_resp) { | ||
2335 | rc = -ENOMEM; | ||
2336 | goto error_frame; | ||
2337 | } | 2325 | } |
2338 | 2326 | ||
2339 | in_frame = (struct pn533_frame *) skb_resp->data; | 2327 | if (rc == 0) /* success */ |
2340 | out_frame = (struct pn533_frame *) skb_cmd->data; | ||
2341 | |||
2342 | arg->skb_resp = skb_resp; | ||
2343 | arg->skb_out = skb_cmd; | ||
2344 | |||
2345 | rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, | ||
2346 | skb_resp_len, | ||
2347 | pn533_data_exchange_complete, | ||
2348 | dev->cmd_complete_arg); | ||
2349 | if (!rc) | ||
2350 | return; | 2328 | return; |
2351 | 2329 | ||
2352 | nfc_dev_err(&dev->interface->dev, "Error %d when trying to" | 2330 | nfc_dev_err(&dev->interface->dev, |
2353 | " perform data_exchange", rc); | 2331 | "Error %d when trying to perform data_exchange", rc); |
2354 | |||
2355 | kfree_skb(skb_resp); | ||
2356 | 2332 | ||
2357 | error_frame: | 2333 | dev_kfree_skb(skb); |
2358 | kfree_skb(skb_cmd); | 2334 | kfree(dev->cmd_complete_arg); |
2359 | 2335 | ||
2360 | error_cmd: | 2336 | error: |
2361 | pn533_send_ack(dev, GFP_KERNEL); | 2337 | pn533_send_ack(dev, GFP_KERNEL); |
2362 | |||
2363 | kfree(arg); | ||
2364 | |||
2365 | queue_work(dev->wq, &dev->cmd_work); | 2338 | queue_work(dev->wq, &dev->cmd_work); |
2366 | } | 2339 | } |
2367 | 2340 | ||