nfc test on MQX4.1
[nfc-test.git] / pcd-fio.c
blob213a65fdcdf786fc39818b11132b96fff20a8ee2
2 #include "common.h"
3 #include "picc.h"
5 struct pcd_param
7 uint8_t *p_iBuf;
8 uint8_t *p_oBuf;
9 uint32_t iDataLen;
10 uint32_t oDataLen;
11 uint32_t statusCode;
14 #define Card_PowerOn 0x01
15 #define Card_PowerOff 0x02
16 #define Card_XfrAPDU 0x03
19 void run_picc_poll(struct work_struct *work);
20 DECLARE_DELAYED_WORK(card_Poll, run_picc_poll);
23 struct pcd_common
25 struct pcd_device pcd;
26 struct picc_device picc;
28 OS_Sem_handle mutex;
29 uint8_t sem_inc;
30 struct workqueue_struct *polling;
32 int (*slot_changed_notify)(void *, uint8_t);
33 void *private_data;
37 struct pcd_common *common = NULL;
39 #include "picc.c"
40 #include "ccid_picc.c"
43 static long pcd_ioctl(struct file *filp, u32 cmd, unsigned long arg)
45 struct pcd_common *common = filp->private_data;
46 u8 pcd_cmd = (cmd >> 4) & 0xFF;
47 struct pcd_param KerParam;
48 struct pcd_param *UsrParam = (struct pcd_param *)arg;
49 u8 *p_iData;
50 u8 *p_oData;
51 u32 ret = 0;
52 u8 level = 0;
55 if(down_interruptible(&common->mutex)) // acquire the semaphore
57 ret = -ERESTARTSYS;
58 goto err;
61 if((!UsrParam) || (copy_from_user(&KerParam, UsrParam, sizeof(KerParam))))
63 ret = -EFAULT; // bad address
64 goto err;
67 switch(pcd_cmd)
69 case Card_PowerOn:
71 if(!KerParam.p_oBuf)
73 ret = -EFAULT; // bad address
74 goto err;
77 p_oData = kmalloc(KerParam.oDataLen, GFP_KERNEL);
79 if(!p_oData)
81 ret = -EFAULT; // bad address
82 goto err;
85 if((ret = picc_power_on(&common->picc, p_oData, &KerParam.oDataLen)) != 0)
86 goto err2;
88 if(copy_to_user(KerParam.p_oBuf, p_oData, KerParam.oDataLen))
90 ret = -EFAULT; // bad address
91 goto err2;
94 if(copy_to_user(&UsrParam->oDataLen, &KerParam.oDataLen, sizeof(KerParam.oDataLen)))
96 ret = -EFAULT; // bad address
97 goto err2;
100 kfree(p_oData);
102 break;
105 case Card_PowerOff:
107 picc_power_off(&common->picc);
108 ret = 0;
109 break;
112 case Card_XfrAPDU:
114 if((KerParam.iDataLen <= 0) || (KerParam.oDataLen <= 0) || (!KerParam.p_iBuf) || (!KerParam.p_oBuf))
116 ret = -EFAULT; // bad address
117 goto err;
120 p_iData = kmalloc(KerParam.iDataLen, GFP_KERNEL);
121 p_oData = kmalloc(KerParam.oDataLen, GFP_KERNEL);
123 if((!p_iData) || (!p_oData) || (copy_from_user(p_iData, KerParam.p_iBuf, KerParam.iDataLen)))
125 ret = -EFAULT; // bad address
126 goto err1;
129 if((ret = picc_command_exchange(&common->picc, p_iData, KerParam.iDataLen, p_oData, &KerParam.oDataLen, &level)) != 0)
130 goto err;
132 if((KerParam.oDataLen <= 0) || (copy_to_user(KerParam.p_oBuf, p_oData, (unsigned long)KerParam.oDataLen)))
134 ret = -EFAULT; // bad address
135 goto err1;
138 if(copy_to_user(&UsrParam->oDataLen, &KerParam.oDataLen, sizeof(KerParam.oDataLen)))
140 ret = -EFAULT; // bad address
141 goto err1;
144 kfree(p_iData);
145 kfree(p_oData);
147 break;
150 default:
151 break;
154 up(&common->mutex);
155 return(0);
158 err1:
159 if(p_iData) kfree(p_iData);
160 err2:
161 if(p_oData) kfree(p_oData);
162 err:
163 up(&common->mutex); // release the semaphore
164 UsrParam->statusCode = ret;
165 return(ret);
169 static int pcd_open(struct inode *inode, struct file *filp)
171 if(common->sem_inc > 0) return(-ERESTARTSYS);
172 common->sem_inc++;
174 filp->private_data = common;
176 return(0);
178 static int pcd_release(struct inode *inode, struct file *filp)
180 struct pcd_common *common = filp->private_data;
183 common->sem_inc--;
185 return(0);
188 extern int picc_interrput_in(u8 slot_status);
190 void run_picc_poll(struct work_struct *work)
194 if(down_trylock(&common->mutex))
196 goto done;
199 if(BITISSET(common->pcd.flags_polling, AUTO_POLLING) && BITISSET(common->pcd.flags_polling, POLLING_CARD_ENABLE))
201 picc_polling_tags(&common->picc);
203 if(BITISSET(common->picc.status, SLOT_CHANGE))
205 if(!picc_interrput_in(common->picc.status & PRESENT))
206 CLEAR_BIT(common->picc.status, SLOT_CHANGE);
212 up(&common->mutex);
214 done:
216 queue_delayed_work(common->polling, &card_Poll, (common->pcd.poll_interval * HZ) / 1000);
222 static struct file_operations pcd_fops=
224 .owner = THIS_MODULE,
225 .open = pcd_open,
226 .unlocked_ioctl = pcd_ioctl,
227 .release = pcd_release
230 static struct miscdevice pcd_misc=
232 .minor = 221,
233 .name = "pcd",
234 .fops = &pcd_fops
237 static int pcd_init(void)
239 int ret;
242 TRACE_TO("enter %s\n", __func__);
244 common = kzalloc(sizeof *common, GFP_KERNEL);
245 if (!common)
247 ret = -ENOMEM;
248 goto err1;
251 sema_init(&common->mutex, 0); // initial a semaphore, and lock it
253 ret = picc_init(common);
254 if(ret)
255 goto err2;
257 ret = misc_register(&pcd_misc);
258 if(ret)
260 ERROR_TO("fail to register device\n");
261 goto err3;
264 common->polling = create_singlethread_workqueue("polling picc");
265 if(!common->polling)
267 ERROR_TO("can't create work queue 'pcdPoll'\n");
268 ret = -EFAULT;
269 goto err4;
271 run_picc_poll(0);
273 up(&common->mutex);
275 TRACE_TO("exit %s\n", __func__);
277 return (0);
279 err4:
280 misc_deregister(&pcd_misc);
281 err3:
282 picc_uninit();
283 err2:
284 up(&common->mutex);
285 kfree(common);
286 err1:
288 TRACE_TO("exit %s\n", __func__);
289 return ret;
292 static void pcd_exit(void)
294 TRACE_TO("enter %s\n", __func__);
296 if (down_interruptible(&common->mutex))
298 return;
301 if(!cancel_delayed_work(&card_Poll))
303 flush_workqueue(common->polling);
305 destroy_workqueue(common->polling);
307 picc_uninit();
309 misc_deregister(&pcd_misc);
311 up(&common->mutex);
313 kfree(common);
315 TRACE_TO("exit %s\n", __func__);
317 return;
320 module_init(pcd_init);
321 module_exit(pcd_exit);
322 MODULE_DESCRIPTION("Contactless Card Driver");
323 MODULE_AUTHOR("Alex Wang");
324 MODULE_LICENSE("GPL");