Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.2-rc2 343 lines 7.9 kB view raw
1/* 2 * Texas Instrument's NFC Driver For Shared Transport. 3 * 4 * NFC Driver acts as interface between NCI core and 5 * TI Shared Transport Layer. 6 * 7 * Copyright (C) 2011 Texas Instruments, Inc. 8 * 9 * Written by Ilan Elias <ilane@ti.com> 10 * 11 * Acknowledgements: 12 * This file is based on btwilink.c, which was written 13 * by Raja Mani and Pavan Savoy. 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License version 2 as 17 * published by the Free Software Foundation. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * 28 */ 29#include <linux/platform_device.h> 30#include <linux/module.h> 31#include <linux/nfc.h> 32#include <net/nfc/nci.h> 33#include <net/nfc/nci_core.h> 34#include <linux/ti_wilink_st.h> 35 36#define NFCWILINK_CHNL 12 37#define NFCWILINK_OPCODE 7 38#define NFCWILINK_MAX_FRAME_SIZE 300 39#define NFCWILINK_HDR_LEN 4 40#define NFCWILINK_OFFSET_LEN_IN_HDR 1 41#define NFCWILINK_LEN_SIZE 2 42#define NFCWILINK_REGISTER_TIMEOUT 8000 /* 8 sec */ 43 44struct nfcwilink_hdr { 45 u8 chnl; 46 u8 opcode; 47 u16 len; 48} __packed; 49 50struct nfcwilink { 51 struct platform_device *pdev; 52 struct nci_dev *ndev; 53 unsigned long flags; 54 55 char st_register_cb_status; 56 long (*st_write) (struct sk_buff *); 57 struct completion st_register_completed; 58}; 59 60/* NFCWILINK driver flags */ 61enum { 62 NFCWILINK_RUNNING, 63}; 64 65/* Called by ST when registration is complete */ 66static void nfcwilink_register_complete(void *priv_data, char data) 67{ 68 struct nfcwilink *drv = priv_data; 69 70 nfc_dev_dbg(&drv->pdev->dev, "register_complete entry"); 71 72 /* store ST registration status */ 73 drv->st_register_cb_status = data; 74 75 /* complete the wait in nfc_st_open() */ 76 complete(&drv->st_register_completed); 77} 78 79/* Called by ST when receive data is available */ 80static long nfcwilink_receive(void *priv_data, struct sk_buff *skb) 81{ 82 struct nfcwilink *drv = priv_data; 83 int rc; 84 85 nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len); 86 87 if (!skb) 88 return -EFAULT; 89 90 if (!drv) { 91 kfree_skb(skb); 92 return -EFAULT; 93 } 94 95 /* strip the ST header 96 (apart for the chnl byte, which is not received in the hdr) */ 97 skb_pull(skb, (NFCWILINK_HDR_LEN-1)); 98 99 skb->dev = (void *) drv->ndev; 100 101 /* Forward skb to NCI core layer */ 102 rc = nci_recv_frame(skb); 103 if (rc < 0) { 104 nfc_dev_err(&drv->pdev->dev, "nci_recv_frame failed %d", rc); 105 return rc; 106 } 107 108 return 0; 109} 110 111/* protocol structure registered with ST */ 112static struct st_proto_s nfcwilink_proto = { 113 .chnl_id = NFCWILINK_CHNL, 114 .max_frame_size = NFCWILINK_MAX_FRAME_SIZE, 115 .hdr_len = (NFCWILINK_HDR_LEN-1), /* not including chnl byte */ 116 .offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR, 117 .len_size = NFCWILINK_LEN_SIZE, 118 .reserve = 0, 119 .recv = nfcwilink_receive, 120 .reg_complete_cb = nfcwilink_register_complete, 121 .write = NULL, 122}; 123 124static int nfcwilink_open(struct nci_dev *ndev) 125{ 126 struct nfcwilink *drv = nci_get_drvdata(ndev); 127 unsigned long comp_ret; 128 int rc; 129 130 nfc_dev_dbg(&drv->pdev->dev, "open entry"); 131 132 if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) { 133 rc = -EBUSY; 134 goto exit; 135 } 136 137 nfcwilink_proto.priv_data = drv; 138 139 init_completion(&drv->st_register_completed); 140 drv->st_register_cb_status = -EINPROGRESS; 141 142 rc = st_register(&nfcwilink_proto); 143 if (rc < 0) { 144 if (rc == -EINPROGRESS) { 145 comp_ret = wait_for_completion_timeout( 146 &drv->st_register_completed, 147 msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT)); 148 149 nfc_dev_dbg(&drv->pdev->dev, 150 "wait_for_completion_timeout returned %ld", 151 comp_ret); 152 153 if (comp_ret == 0) { 154 /* timeout */ 155 rc = -ETIMEDOUT; 156 goto clear_exit; 157 } else if (drv->st_register_cb_status != 0) { 158 rc = drv->st_register_cb_status; 159 nfc_dev_err(&drv->pdev->dev, 160 "st_register_cb failed %d", rc); 161 goto clear_exit; 162 } 163 } else { 164 nfc_dev_err(&drv->pdev->dev, 165 "st_register failed %d", rc); 166 goto clear_exit; 167 } 168 } 169 170 /* st_register MUST fill the write callback */ 171 BUG_ON(nfcwilink_proto.write == NULL); 172 drv->st_write = nfcwilink_proto.write; 173 174 goto exit; 175 176clear_exit: 177 clear_bit(NFCWILINK_RUNNING, &drv->flags); 178 179exit: 180 return rc; 181} 182 183static int nfcwilink_close(struct nci_dev *ndev) 184{ 185 struct nfcwilink *drv = nci_get_drvdata(ndev); 186 int rc; 187 188 nfc_dev_dbg(&drv->pdev->dev, "close entry"); 189 190 if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags)) 191 return 0; 192 193 rc = st_unregister(&nfcwilink_proto); 194 if (rc) 195 nfc_dev_err(&drv->pdev->dev, "st_unregister failed %d", rc); 196 197 drv->st_write = NULL; 198 199 return rc; 200} 201 202static int nfcwilink_send(struct sk_buff *skb) 203{ 204 struct nci_dev *ndev = (struct nci_dev *)skb->dev; 205 struct nfcwilink *drv = nci_get_drvdata(ndev); 206 struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000}; 207 long len; 208 209 nfc_dev_dbg(&drv->pdev->dev, "send entry, len %d", skb->len); 210 211 if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) 212 return -EBUSY; 213 214 /* add the ST hdr to the start of the buffer */ 215 hdr.len = skb->len; 216 memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN); 217 218 /* Insert skb to shared transport layer's transmit queue. 219 * Freeing skb memory is taken care in shared transport layer, 220 * so don't free skb memory here. 221 */ 222 len = drv->st_write(skb); 223 if (len < 0) { 224 kfree_skb(skb); 225 nfc_dev_err(&drv->pdev->dev, "st_write failed %ld", len); 226 return -EFAULT; 227 } 228 229 return 0; 230} 231 232static struct nci_ops nfcwilink_ops = { 233 .open = nfcwilink_open, 234 .close = nfcwilink_close, 235 .send = nfcwilink_send, 236}; 237 238static int nfcwilink_probe(struct platform_device *pdev) 239{ 240 static struct nfcwilink *drv; 241 int rc; 242 u32 protocols; 243 244 nfc_dev_dbg(&pdev->dev, "probe entry"); 245 246 drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL); 247 if (!drv) { 248 rc = -ENOMEM; 249 goto exit; 250 } 251 252 drv->pdev = pdev; 253 254 protocols = NFC_PROTO_JEWEL_MASK 255 | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK 256 | NFC_PROTO_ISO14443_MASK 257 | NFC_PROTO_NFC_DEP_MASK; 258 259 drv->ndev = nci_allocate_device(&nfcwilink_ops, 260 protocols, 261 NFCWILINK_HDR_LEN, 262 0); 263 if (!drv->ndev) { 264 nfc_dev_err(&pdev->dev, "nci_allocate_device failed"); 265 rc = -ENOMEM; 266 goto free_exit; 267 } 268 269 nci_set_parent_dev(drv->ndev, &pdev->dev); 270 nci_set_drvdata(drv->ndev, drv); 271 272 rc = nci_register_device(drv->ndev); 273 if (rc < 0) { 274 nfc_dev_err(&pdev->dev, "nci_register_device failed %d", rc); 275 goto free_dev_exit; 276 } 277 278 dev_set_drvdata(&pdev->dev, drv); 279 280 goto exit; 281 282free_dev_exit: 283 nci_free_device(drv->ndev); 284 285free_exit: 286 kfree(drv); 287 288exit: 289 return rc; 290} 291 292static int nfcwilink_remove(struct platform_device *pdev) 293{ 294 struct nfcwilink *drv = dev_get_drvdata(&pdev->dev); 295 struct nci_dev *ndev; 296 297 nfc_dev_dbg(&pdev->dev, "remove entry"); 298 299 if (!drv) 300 return -EFAULT; 301 302 ndev = drv->ndev; 303 304 nci_unregister_device(ndev); 305 nci_free_device(ndev); 306 307 kfree(drv); 308 309 dev_set_drvdata(&pdev->dev, NULL); 310 311 return 0; 312} 313 314static struct platform_driver nfcwilink_driver = { 315 .probe = nfcwilink_probe, 316 .remove = nfcwilink_remove, 317 .driver = { 318 .name = "nfcwilink", 319 .owner = THIS_MODULE, 320 }, 321}; 322 323/* ------- Module Init/Exit interfaces ------ */ 324static int __init nfcwilink_init(void) 325{ 326 printk(KERN_INFO "NFC Driver for TI WiLink"); 327 328 return platform_driver_register(&nfcwilink_driver); 329} 330 331static void __exit nfcwilink_exit(void) 332{ 333 platform_driver_unregister(&nfcwilink_driver); 334} 335 336module_init(nfcwilink_init); 337module_exit(nfcwilink_exit); 338 339/* ------ Module Info ------ */ 340 341MODULE_AUTHOR("Ilan Elias <ilane@ti.com>"); 342MODULE_DESCRIPTION("NFC Driver for TI Shared Transport"); 343MODULE_LICENSE("GPL");