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
);
25 struct pcd_device pcd
;
26 struct picc_device picc
;
30 struct workqueue_struct
*polling
;
32 int (*slot_changed_notify
)(void *, uint8_t);
37 struct pcd_common
*common
= NULL
;
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
;
55 if(down_interruptible(&common
->mutex
)) // acquire the semaphore
61 if((!UsrParam
) || (copy_from_user(&KerParam
, UsrParam
, sizeof(KerParam
))))
63 ret
= -EFAULT
; // bad address
73 ret
= -EFAULT
; // bad address
77 p_oData
= kmalloc(KerParam
.oDataLen
, GFP_KERNEL
);
81 ret
= -EFAULT
; // bad address
85 if((ret
= picc_power_on(&common
->picc
, p_oData
, &KerParam
.oDataLen
)) != 0)
88 if(copy_to_user(KerParam
.p_oBuf
, p_oData
, KerParam
.oDataLen
))
90 ret
= -EFAULT
; // bad address
94 if(copy_to_user(&UsrParam
->oDataLen
, &KerParam
.oDataLen
, sizeof(KerParam
.oDataLen
)))
96 ret
= -EFAULT
; // bad address
107 picc_power_off(&common
->picc
);
114 if((KerParam
.iDataLen
<= 0) || (KerParam
.oDataLen
<= 0) || (!KerParam
.p_iBuf
) || (!KerParam
.p_oBuf
))
116 ret
= -EFAULT
; // bad address
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
129 if((ret
= picc_command_exchange(&common
->picc
, p_iData
, KerParam
.iDataLen
, p_oData
, &KerParam
.oDataLen
, &level
)) != 0)
132 if((KerParam
.oDataLen
<= 0) || (copy_to_user(KerParam
.p_oBuf
, p_oData
, (unsigned long)KerParam
.oDataLen
)))
134 ret
= -EFAULT
; // bad address
138 if(copy_to_user(&UsrParam
->oDataLen
, &KerParam
.oDataLen
, sizeof(KerParam
.oDataLen
)))
140 ret
= -EFAULT
; // bad address
159 if(p_iData
) kfree(p_iData
);
161 if(p_oData
) kfree(p_oData
);
163 up(&common
->mutex
); // release the semaphore
164 UsrParam
->statusCode
= ret
;
169 static int pcd_open(struct inode
*inode
, struct file
*filp
)
171 if(common
->sem_inc
> 0) return(-ERESTARTSYS
);
174 filp
->private_data
= common
;
178 static int pcd_release(struct inode
*inode
, struct file
*filp
)
180 struct pcd_common
*common
= filp
->private_data
;
188 extern int picc_interrput_in(u8 slot_status
);
190 void run_picc_poll(struct work_struct
*work
)
194 if(down_trylock(&common
->mutex
))
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
);
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
,
226 .unlocked_ioctl
= pcd_ioctl
,
227 .release
= pcd_release
230 static struct miscdevice pcd_misc
=
237 static int pcd_init(void)
242 TRACE_TO("enter %s\n", __func__
);
244 common
= kzalloc(sizeof *common
, GFP_KERNEL
);
251 sema_init(&common
->mutex
, 0); // initial a semaphore, and lock it
253 ret
= picc_init(common
);
257 ret
= misc_register(&pcd_misc
);
260 ERROR_TO("fail to register device\n");
264 common
->polling
= create_singlethread_workqueue("polling picc");
267 ERROR_TO("can't create work queue 'pcdPoll'\n");
275 TRACE_TO("exit %s\n", __func__
);
280 misc_deregister(&pcd_misc
);
288 TRACE_TO("exit %s\n", __func__
);
292 static void pcd_exit(void)
294 TRACE_TO("enter %s\n", __func__
);
296 if (down_interruptible(&common
->mutex
))
301 if(!cancel_delayed_work(&card_Poll
))
303 flush_workqueue(common
->polling
);
305 destroy_workqueue(common
->polling
);
309 misc_deregister(&pcd_misc
);
315 TRACE_TO("exit %s\n", __func__
);
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");