2012-05-07 14:31:29 +04:00
/*
* HCI based Driver for NXP PN544 NFC Chip
*
* Copyright ( C ) 2012 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the
* Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <linux/delay.h>
# include <linux/slab.h>
2012-12-18 19:26:23 +04:00
# include <linux/module.h>
2012-05-07 14:31:29 +04:00
# include <linux/nfc.h>
# include <net/nfc/hci.h>
2012-09-18 21:45:48 +04:00
# include <net/nfc/llc.h>
2012-05-07 14:31:29 +04:00
2012-10-02 20:44:06 +04:00
# include "pn544.h"
2012-05-07 14:31:29 +04:00
/* Timing restrictions (ms) */
# define PN544_HCI_RESETVEN_TIME 30
# define HCI_MODE 0
# define FW_MODE 1
enum pn544_state {
PN544_ST_COLD ,
PN544_ST_FW_READY ,
PN544_ST_READY ,
} ;
# define FULL_VERSION_LEN 11
/* Proprietary commands */
# define PN544_WRITE 0x3f
/* Proprietary gates, events, commands and registers */
/* NFC_HCI_RF_READER_A_GATE additional registers and commands */
# define PN544_RF_READER_A_AUTO_ACTIVATION 0x10
# define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12
# define PN544_MIFARE_CMD 0x21
/* Commands that apply to all RF readers */
# define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30
# define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32
/* NFC_HCI_ID_MGMT_GATE additional registers */
# define PN544_ID_MGMT_FULL_VERSION_SW 0x10
# define PN544_RF_READER_ISO15693_GATE 0x12
# define PN544_RF_READER_F_GATE 0x14
# define PN544_FELICA_ID 0x04
# define PN544_FELICA_RAW 0x20
# define PN544_RF_READER_JEWEL_GATE 0x15
# define PN544_JEWEL_RAW_CMD 0x23
# define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30
# define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31
# define PN544_SYS_MGMT_GATE 0x90
# define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02
# define PN544_POLLING_LOOP_MGMT_GATE 0x94
2012-09-27 13:32:54 +04:00
# define PN544_DEP_MODE 0x01
# define PN544_DEP_ATR_REQ 0x02
# define PN544_DEP_ATR_RES 0x03
# define PN544_DEP_MERGE 0x0D
2012-05-07 14:31:29 +04:00
# define PN544_PL_RDPHASES 0x06
# define PN544_PL_EMULATION 0x07
# define PN544_PL_NFCT_DEACTIVATED 0x09
# define PN544_SWP_MGMT_GATE 0xA0
# define PN544_NFC_WI_MGMT_GATE 0xA1
2012-09-27 13:32:55 +04:00
# define PN544_HCI_EVT_SND_DATA 0x01
# define PN544_HCI_EVT_ACTIVATED 0x02
# define PN544_HCI_EVT_DEACTIVATED 0x03
# define PN544_HCI_EVT_RCV_DATA 0x04
# define PN544_HCI_EVT_CONTINUE_MI 0x05
2012-09-27 13:32:59 +04:00
# define PN544_HCI_CMD_ATTREQUEST 0x12
2012-09-27 13:32:56 +04:00
# define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13
2012-06-05 16:42:11 +04:00
static struct nfc_hci_gate pn544_gates [ ] = {
{ NFC_HCI_ADMIN_GATE , NFC_HCI_INVALID_PIPE } ,
{ NFC_HCI_LOOPBACK_GATE , NFC_HCI_INVALID_PIPE } ,
{ NFC_HCI_ID_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ NFC_HCI_LINK_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ NFC_HCI_RF_READER_B_GATE , NFC_HCI_INVALID_PIPE } ,
{ NFC_HCI_RF_READER_A_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_SYS_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_SWP_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_POLLING_LOOP_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_NFC_WI_MGMT_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_RF_READER_F_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_RF_READER_JEWEL_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_RF_READER_ISO15693_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_RF_READER_NFCIP1_INITIATOR_GATE , NFC_HCI_INVALID_PIPE } ,
{ PN544_RF_READER_NFCIP1_TARGET_GATE , NFC_HCI_INVALID_PIPE }
2012-05-07 14:31:29 +04:00
} ;
/* Largest headroom needed for outgoing custom commands */
# define PN544_CMDS_HEADROOM 2
struct pn544_hci_info {
2012-10-02 20:44:06 +04:00
struct nfc_phy_ops * phy_ops ;
void * phy_id ;
2012-09-18 21:45:48 +04:00
struct nfc_hci_dev * hdev ;
2012-05-07 14:31:29 +04:00
enum pn544_state state ;
struct mutex info_lock ;
2012-09-11 12:43:50 +04:00
int async_cb_type ;
data_exchange_cb_t async_cb ;
void * async_cb_context ;
2012-05-07 14:31:29 +04:00
} ;
2012-09-18 21:45:48 +04:00
static int pn544_hci_open ( struct nfc_hci_dev * hdev )
2012-05-07 14:31:29 +04:00
{
2012-09-18 21:45:48 +04:00
struct pn544_hci_info * info = nfc_hci_get_clientdata ( hdev ) ;
2012-05-07 14:31:29 +04:00
int r = 0 ;
mutex_lock ( & info - > info_lock ) ;
if ( info - > state ! = PN544_ST_COLD ) {
r = - EBUSY ;
goto out ;
}
2012-10-02 20:44:06 +04:00
r = info - > phy_ops - > enable ( info - > phy_id ) ;
2012-05-07 14:31:29 +04:00
2012-05-30 20:13:06 +04:00
if ( r = = 0 )
info - > state = PN544_ST_READY ;
2012-05-07 14:31:29 +04:00
out :
mutex_unlock ( & info - > info_lock ) ;
return r ;
}
2012-09-18 21:45:48 +04:00
static void pn544_hci_close ( struct nfc_hci_dev * hdev )
2012-05-07 14:31:29 +04:00
{
2012-09-18 21:45:48 +04:00
struct pn544_hci_info * info = nfc_hci_get_clientdata ( hdev ) ;
2012-05-07 14:31:29 +04:00
mutex_lock ( & info - > info_lock ) ;
if ( info - > state = = PN544_ST_COLD )
goto out ;
2012-10-02 20:44:06 +04:00
info - > phy_ops - > disable ( info - > phy_id ) ;
2012-05-07 14:31:29 +04:00
2012-05-30 20:13:06 +04:00
info - > state = PN544_ST_COLD ;
2012-05-07 14:31:29 +04:00
out :
mutex_unlock ( & info - > info_lock ) ;
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_ready ( struct nfc_hci_dev * hdev )
2012-05-07 14:31:29 +04:00
{
struct sk_buff * skb ;
static struct hw_config {
u8 adr [ 2 ] ;
u8 value ;
} hw_config [ ] = {
{ { 0x9f , 0x9a } , 0x00 } ,
{ { 0x98 , 0x10 } , 0xbc } ,
{ { 0x9e , 0x71 } , 0x00 } ,
{ { 0x98 , 0x09 } , 0x00 } ,
{ { 0x9e , 0xb4 } , 0x00 } ,
{ { 0x9e , 0xd9 } , 0xff } ,
{ { 0x9e , 0xda } , 0xff } ,
{ { 0x9e , 0xdb } , 0x23 } ,
{ { 0x9e , 0xdc } , 0x21 } ,
{ { 0x9e , 0xdd } , 0x22 } ,
{ { 0x9e , 0xde } , 0x24 } ,
{ { 0x9c , 0x01 } , 0x08 } ,
{ { 0x9e , 0xaa } , 0x01 } ,
{ { 0x9b , 0xd1 } , 0x0d } ,
{ { 0x9b , 0xd2 } , 0x24 } ,
{ { 0x9b , 0xd3 } , 0x0a } ,
{ { 0x9b , 0xd4 } , 0x22 } ,
{ { 0x9b , 0xd5 } , 0x08 } ,
{ { 0x9b , 0xd6 } , 0x1e } ,
{ { 0x9b , 0xdd } , 0x1c } ,
{ { 0x9b , 0x84 } , 0x13 } ,
{ { 0x99 , 0x81 } , 0x7f } ,
{ { 0x99 , 0x31 } , 0x70 } ,
{ { 0x98 , 0x00 } , 0x3f } ,
{ { 0x9f , 0x09 } , 0x00 } ,
{ { 0x9f , 0x0a } , 0x05 } ,
{ { 0x9e , 0xd1 } , 0xa1 } ,
{ { 0x99 , 0x23 } , 0x00 } ,
{ { 0x9e , 0x74 } , 0x80 } ,
{ { 0x9f , 0x28 } , 0x10 } ,
{ { 0x9f , 0x35 } , 0x14 } ,
{ { 0x9f , 0x36 } , 0x60 } ,
{ { 0x9c , 0x31 } , 0x00 } ,
{ { 0x9c , 0x32 } , 0xc8 } ,
{ { 0x9c , 0x19 } , 0x40 } ,
{ { 0x9c , 0x1a } , 0x40 } ,
{ { 0x9c , 0x0c } , 0x00 } ,
{ { 0x9c , 0x0d } , 0x00 } ,
{ { 0x9c , 0x12 } , 0x00 } ,
{ { 0x9c , 0x13 } , 0x00 } ,
{ { 0x98 , 0xa2 } , 0x0e } ,
{ { 0x98 , 0x93 } , 0x40 } ,
{ { 0x98 , 0x7d } , 0x02 } ,
{ { 0x98 , 0x7e } , 0x00 } ,
{ { 0x9f , 0xc8 } , 0x01 } ,
} ;
struct hw_config * p = hw_config ;
int count = ARRAY_SIZE ( hw_config ) ;
struct sk_buff * res_skb ;
u8 param [ 4 ] ;
int r ;
param [ 0 ] = 0 ;
while ( count - - ) {
param [ 1 ] = p - > adr [ 0 ] ;
param [ 2 ] = p - > adr [ 1 ] ;
param [ 3 ] = p - > value ;
r = nfc_hci_send_cmd ( hdev , PN544_SYS_MGMT_GATE , PN544_WRITE ,
param , 4 , & res_skb ) ;
if ( r < 0 )
return r ;
if ( res_skb - > len ! = 1 ) {
kfree_skb ( res_skb ) ;
return - EPROTO ;
}
if ( res_skb - > data [ 0 ] ! = p - > value ) {
kfree_skb ( res_skb ) ;
return - EIO ;
}
kfree_skb ( res_skb ) ;
p + + ;
}
param [ 0 ] = NFC_HCI_UICC_HOST_ID ;
r = nfc_hci_set_param ( hdev , NFC_HCI_ADMIN_GATE ,
NFC_HCI_ADMIN_WHITELIST , param , 1 ) ;
if ( r < 0 )
return r ;
param [ 0 ] = 0x3d ;
r = nfc_hci_set_param ( hdev , PN544_SYS_MGMT_GATE ,
PN544_SYS_MGMT_INFO_NOTIFICATION , param , 1 ) ;
if ( r < 0 )
return r ;
param [ 0 ] = 0x0 ;
r = nfc_hci_set_param ( hdev , NFC_HCI_RF_READER_A_GATE ,
PN544_RF_READER_A_AUTO_ACTIVATION , param , 1 ) ;
if ( r < 0 )
return r ;
r = nfc_hci_send_event ( hdev , NFC_HCI_RF_READER_A_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
if ( r < 0 )
return r ;
param [ 0 ] = 0x1 ;
r = nfc_hci_set_param ( hdev , PN544_POLLING_LOOP_MGMT_GATE ,
PN544_PL_NFCT_DEACTIVATED , param , 1 ) ;
if ( r < 0 )
return r ;
param [ 0 ] = 0x0 ;
r = nfc_hci_set_param ( hdev , PN544_POLLING_LOOP_MGMT_GATE ,
PN544_PL_RDPHASES , param , 1 ) ;
if ( r < 0 )
return r ;
r = nfc_hci_get_param ( hdev , NFC_HCI_ID_MGMT_GATE ,
PN544_ID_MGMT_FULL_VERSION_SW , & skb ) ;
if ( r < 0 )
return r ;
if ( skb - > len ! = FULL_VERSION_LEN ) {
kfree_skb ( skb ) ;
return - EINVAL ;
}
print_hex_dump ( KERN_DEBUG , " FULL VERSION SOFTWARE INFO: " ,
DUMP_PREFIX_NONE , 16 , 1 ,
skb - > data , FULL_VERSION_LEN , false ) ;
kfree_skb ( skb ) ;
return 0 ;
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_xmit ( struct nfc_hci_dev * hdev , struct sk_buff * skb )
2012-05-07 14:31:29 +04:00
{
2012-09-18 21:45:48 +04:00
struct pn544_hci_info * info = nfc_hci_get_clientdata ( hdev ) ;
2012-09-07 13:08:29 +04:00
2012-10-02 20:44:06 +04:00
return info - > phy_ops - > write ( info - > phy_id , skb ) ;
2012-05-07 14:31:29 +04:00
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_start_poll ( struct nfc_hci_dev * hdev ,
2012-05-15 17:57:06 +04:00
u32 im_protocols , u32 tm_protocols )
2012-05-07 14:31:29 +04:00
{
u8 phases = 0 ;
int r ;
u8 duration [ 2 ] ;
u8 activated ;
2012-09-27 13:32:54 +04:00
u8 i_mode = 0x3f ; /* Enable all supported modes */
u8 t_mode = 0x0f ;
u8 t_merge = 0x01 ; /* Enable merge by default */
2012-05-07 14:31:29 +04:00
2012-05-15 17:57:06 +04:00
pr_info ( DRIVER_DESC " : %s protocols 0x%x 0x%x \n " ,
__func__ , im_protocols , tm_protocols ) ;
2012-05-07 14:31:29 +04:00
r = nfc_hci_send_event ( hdev , NFC_HCI_RF_READER_A_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
if ( r < 0 )
return r ;
duration [ 0 ] = 0x18 ;
duration [ 1 ] = 0x6a ;
r = nfc_hci_set_param ( hdev , PN544_POLLING_LOOP_MGMT_GATE ,
PN544_PL_EMULATION , duration , 2 ) ;
if ( r < 0 )
return r ;
activated = 0 ;
r = nfc_hci_set_param ( hdev , PN544_POLLING_LOOP_MGMT_GATE ,
PN544_PL_NFCT_DEACTIVATED , & activated , 1 ) ;
if ( r < 0 )
return r ;
2012-05-15 17:57:06 +04:00
if ( im_protocols & ( NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
2012-05-07 14:31:29 +04:00
NFC_PROTO_JEWEL_MASK ) )
phases | = 1 ; /* Type A */
2012-05-15 17:57:06 +04:00
if ( im_protocols & NFC_PROTO_FELICA_MASK ) {
2012-05-07 14:31:29 +04:00
phases | = ( 1 < < 2 ) ; /* Type F 212 */
phases | = ( 1 < < 3 ) ; /* Type F 424 */
}
phases | = ( 1 < < 5 ) ; /* NFC active */
r = nfc_hci_set_param ( hdev , PN544_POLLING_LOOP_MGMT_GATE ,
PN544_PL_RDPHASES , & phases , 1 ) ;
if ( r < 0 )
return r ;
2012-09-27 13:32:54 +04:00
if ( ( im_protocols | tm_protocols ) & NFC_PROTO_NFC_DEP_MASK ) {
hdev - > gb = nfc_get_local_general_bytes ( hdev - > ndev ,
& hdev - > gb_len ) ;
pr_debug ( " generate local bytes %p " , hdev - > gb ) ;
if ( hdev - > gb = = NULL | | hdev - > gb_len = = 0 ) {
im_protocols & = ~ NFC_PROTO_NFC_DEP_MASK ;
tm_protocols & = ~ NFC_PROTO_NFC_DEP_MASK ;
}
}
if ( im_protocols & NFC_PROTO_NFC_DEP_MASK ) {
r = nfc_hci_send_event ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
if ( r < 0 )
return r ;
r = nfc_hci_set_param ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
PN544_DEP_MODE , & i_mode , 1 ) ;
if ( r < 0 )
return r ;
r = nfc_hci_set_param ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
PN544_DEP_ATR_REQ , hdev - > gb , hdev - > gb_len ) ;
if ( r < 0 )
return r ;
r = nfc_hci_send_event ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
NFC_HCI_EVT_READER_REQUESTED , NULL , 0 ) ;
if ( r < 0 )
nfc_hci_send_event ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
}
if ( tm_protocols & NFC_PROTO_NFC_DEP_MASK ) {
r = nfc_hci_set_param ( hdev , PN544_RF_READER_NFCIP1_TARGET_GATE ,
PN544_DEP_MODE , & t_mode , 1 ) ;
if ( r < 0 )
return r ;
r = nfc_hci_set_param ( hdev , PN544_RF_READER_NFCIP1_TARGET_GATE ,
PN544_DEP_ATR_RES , hdev - > gb , hdev - > gb_len ) ;
if ( r < 0 )
return r ;
r = nfc_hci_set_param ( hdev , PN544_RF_READER_NFCIP1_TARGET_GATE ,
PN544_DEP_MERGE , & t_merge , 1 ) ;
if ( r < 0 )
return r ;
}
2012-05-07 14:31:29 +04:00
r = nfc_hci_send_event ( hdev , NFC_HCI_RF_READER_A_GATE ,
NFC_HCI_EVT_READER_REQUESTED , NULL , 0 ) ;
if ( r < 0 )
nfc_hci_send_event ( hdev , NFC_HCI_RF_READER_A_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
return r ;
}
2012-09-27 13:32:57 +04:00
static int pn544_hci_dep_link_up ( struct nfc_hci_dev * hdev ,
struct nfc_target * target , u8 comm_mode ,
u8 * gb , size_t gb_len )
{
struct sk_buff * rgb_skb = NULL ;
int r ;
r = nfc_hci_get_param ( hdev , target - > hci_reader_gate ,
PN544_DEP_ATR_RES , & rgb_skb ) ;
if ( r < 0 )
return r ;
if ( rgb_skb - > len = = 0 | | rgb_skb - > len > NFC_GB_MAXSIZE ) {
r = - EPROTO ;
goto exit ;
}
print_hex_dump ( KERN_DEBUG , " remote gb: " , DUMP_PREFIX_OFFSET ,
16 , 1 , rgb_skb - > data , rgb_skb - > len , true ) ;
r = nfc_set_remote_general_bytes ( hdev - > ndev , rgb_skb - > data ,
rgb_skb - > len ) ;
if ( r = = 0 )
r = nfc_dep_link_is_up ( hdev - > ndev , target - > idx , comm_mode ,
NFC_RF_INITIATOR ) ;
exit :
kfree_skb ( rgb_skb ) ;
return r ;
}
static int pn544_hci_dep_link_down ( struct nfc_hci_dev * hdev )
{
return nfc_hci_send_event ( hdev , PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
NFC_HCI_EVT_END_OPERATION , NULL , 0 ) ;
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_target_from_gate ( struct nfc_hci_dev * hdev , u8 gate ,
2012-05-07 14:31:29 +04:00
struct nfc_target * target )
{
switch ( gate ) {
case PN544_RF_READER_F_GATE :
target - > supported_protocols = NFC_PROTO_FELICA_MASK ;
break ;
case PN544_RF_READER_JEWEL_GATE :
target - > supported_protocols = NFC_PROTO_JEWEL_MASK ;
target - > sens_res = 0x0c00 ;
break ;
2012-09-27 13:32:56 +04:00
case PN544_RF_READER_NFCIP1_INITIATOR_GATE :
target - > supported_protocols = NFC_PROTO_NFC_DEP_MASK ;
break ;
2012-05-07 14:31:29 +04:00
default :
return - EPROTO ;
}
return 0 ;
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_complete_target_discovered ( struct nfc_hci_dev * hdev ,
2012-05-07 14:31:29 +04:00
u8 gate ,
struct nfc_target * target )
{
struct sk_buff * uid_skb ;
int r = 0 ;
2012-09-27 13:32:56 +04:00
if ( gate = = PN544_RF_READER_NFCIP1_INITIATOR_GATE )
return r ;
if ( target - > supported_protocols & NFC_PROTO_NFC_DEP_MASK ) {
r = nfc_hci_send_cmd ( hdev ,
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
PN544_HCI_CMD_CONTINUE_ACTIVATION , NULL , 0 , NULL ) ;
if ( r < 0 )
return r ;
target - > hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE ;
} else if ( target - > supported_protocols & NFC_PROTO_MIFARE_MASK ) {
2012-05-07 14:31:29 +04:00
if ( target - > nfcid1_len ! = 4 & & target - > nfcid1_len ! = 7 & &
target - > nfcid1_len ! = 10 )
return - EPROTO ;
r = nfc_hci_send_cmd ( hdev , NFC_HCI_RF_READER_A_GATE ,
PN544_RF_READER_CMD_ACTIVATE_NEXT ,
target - > nfcid1 , target - > nfcid1_len , NULL ) ;
} else if ( target - > supported_protocols & NFC_PROTO_FELICA_MASK ) {
r = nfc_hci_get_param ( hdev , PN544_RF_READER_F_GATE ,
PN544_FELICA_ID , & uid_skb ) ;
if ( r < 0 )
return r ;
if ( uid_skb - > len ! = 8 ) {
kfree_skb ( uid_skb ) ;
return - EPROTO ;
}
2013-04-22 13:21:04 +04:00
/* Type F NFC-DEP IDm has prefix 0x01FE */
if ( ( uid_skb - > data [ 0 ] = = 0x01 ) & & ( uid_skb - > data [ 1 ] = = 0xfe ) ) {
kfree_skb ( uid_skb ) ;
r = nfc_hci_send_cmd ( hdev ,
2012-09-27 13:32:56 +04:00
PN544_RF_READER_NFCIP1_INITIATOR_GATE ,
PN544_HCI_CMD_CONTINUE_ACTIVATION ,
NULL , 0 , NULL ) ;
2013-04-22 13:21:04 +04:00
if ( r < 0 )
return r ;
target - > supported_protocols = NFC_PROTO_NFC_DEP_MASK ;
target - > hci_reader_gate =
PN544_RF_READER_NFCIP1_INITIATOR_GATE ;
} else {
r = nfc_hci_send_cmd ( hdev , PN544_RF_READER_F_GATE ,
PN544_RF_READER_CMD_ACTIVATE_NEXT ,
uid_skb - > data , uid_skb - > len , NULL ) ;
kfree_skb ( uid_skb ) ;
}
2012-05-07 14:31:29 +04:00
} else if ( target - > supported_protocols & NFC_PROTO_ISO14443_MASK ) {
/*
* TODO : maybe other ISO 14443 require some kind of continue
* activation , but for now we ' ve seen only this one below .
*/
if ( target - > sens_res = = 0x4403 ) /* Type 4 Mifare DESFire */
r = nfc_hci_send_cmd ( hdev , NFC_HCI_RF_READER_A_GATE ,
PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION ,
NULL , 0 , NULL ) ;
}
return r ;
}
2012-09-11 12:43:50 +04:00
# define PN544_CB_TYPE_READER_F 1
static void pn544_hci_data_exchange_cb ( void * context , struct sk_buff * skb ,
int err )
{
struct pn544_hci_info * info = context ;
switch ( info - > async_cb_type ) {
case PN544_CB_TYPE_READER_F :
if ( err = = 0 )
skb_pull ( skb , 1 ) ;
info - > async_cb ( info - > async_cb_context , skb , err ) ;
break ;
default :
if ( err = = 0 )
kfree_skb ( skb ) ;
break ;
}
}
2012-05-07 14:31:29 +04:00
# define MIFARE_CMD_AUTH_KEY_A 0x60
# define MIFARE_CMD_AUTH_KEY_B 0x61
# define MIFARE_CMD_HEADER 2
# define MIFARE_UID_LEN 4
# define MIFARE_KEY_LEN 6
# define MIFARE_CMD_LEN 12
/*
* Returns :
* < = 0 : driver handled the data exchange
* 1 : driver doesn ' t especially handle , please do standard processing
*/
2012-09-27 13:32:58 +04:00
static int pn544_hci_im_transceive ( struct nfc_hci_dev * hdev ,
2012-05-07 14:31:29 +04:00
struct nfc_target * target ,
2012-09-11 12:43:50 +04:00
struct sk_buff * skb , data_exchange_cb_t cb ,
void * cb_context )
2012-05-07 14:31:29 +04:00
{
2012-09-18 21:45:48 +04:00
struct pn544_hci_info * info = nfc_hci_get_clientdata ( hdev ) ;
2012-05-07 14:31:29 +04:00
pr_info ( DRIVER_DESC " : %s for gate=%d \n " , __func__ ,
target - > hci_reader_gate ) ;
switch ( target - > hci_reader_gate ) {
case NFC_HCI_RF_READER_A_GATE :
if ( target - > supported_protocols & NFC_PROTO_MIFARE_MASK ) {
/*
* It seems that pn544 is inverting key and UID for
* MIFARE authentication commands .
*/
if ( skb - > len = = MIFARE_CMD_LEN & &
( skb - > data [ 0 ] = = MIFARE_CMD_AUTH_KEY_A | |
skb - > data [ 0 ] = = MIFARE_CMD_AUTH_KEY_B ) ) {
u8 uid [ MIFARE_UID_LEN ] ;
u8 * data = skb - > data + MIFARE_CMD_HEADER ;
memcpy ( uid , data + MIFARE_KEY_LEN ,
MIFARE_UID_LEN ) ;
memmove ( data + MIFARE_UID_LEN , data ,
MIFARE_KEY_LEN ) ;
memcpy ( data , uid , MIFARE_UID_LEN ) ;
}
2012-09-11 12:43:50 +04:00
return nfc_hci_send_cmd_async ( hdev ,
target - > hci_reader_gate ,
PN544_MIFARE_CMD ,
skb - > data , skb - > len ,
cb , cb_context ) ;
2012-05-07 14:31:29 +04:00
} else
return 1 ;
case PN544_RF_READER_F_GATE :
* skb_push ( skb , 1 ) = 0 ;
* skb_push ( skb , 1 ) = 0 ;
2012-09-11 12:43:50 +04:00
info - > async_cb_type = PN544_CB_TYPE_READER_F ;
info - > async_cb = cb ;
info - > async_cb_context = cb_context ;
return nfc_hci_send_cmd_async ( hdev , target - > hci_reader_gate ,
PN544_FELICA_RAW , skb - > data ,
skb - > len ,
pn544_hci_data_exchange_cb , info ) ;
2012-05-07 14:31:29 +04:00
case PN544_RF_READER_JEWEL_GATE :
2012-09-11 12:43:50 +04:00
return nfc_hci_send_cmd_async ( hdev , target - > hci_reader_gate ,
PN544_JEWEL_RAW_CMD , skb - > data ,
skb - > len , cb , cb_context ) ;
2012-09-27 13:32:58 +04:00
case PN544_RF_READER_NFCIP1_INITIATOR_GATE :
* skb_push ( skb , 1 ) = 0 ;
return nfc_hci_send_event ( hdev , target - > hci_reader_gate ,
PN544_HCI_EVT_SND_DATA , skb - > data ,
skb - > len ) ;
2012-05-07 14:31:29 +04:00
default :
return 1 ;
}
}
2012-09-27 13:32:58 +04:00
static int pn544_hci_tm_send ( struct nfc_hci_dev * hdev , struct sk_buff * skb )
{
2012-12-04 19:44:25 +04:00
int r ;
2012-09-27 13:32:58 +04:00
/* Set default false for multiple information chaining */
* skb_push ( skb , 1 ) = 0 ;
2012-12-04 19:44:25 +04:00
r = nfc_hci_send_event ( hdev , PN544_RF_READER_NFCIP1_TARGET_GATE ,
PN544_HCI_EVT_SND_DATA , skb - > data , skb - > len ) ;
kfree_skb ( skb ) ;
return r ;
2012-09-27 13:32:58 +04:00
}
2012-09-18 21:45:48 +04:00
static int pn544_hci_check_presence ( struct nfc_hci_dev * hdev ,
2012-05-07 14:31:29 +04:00
struct nfc_target * target )
{
2012-09-27 13:32:59 +04:00
pr_debug ( " supported protocol %d " , target - > supported_protocols ) ;
if ( target - > supported_protocols & ( NFC_PROTO_ISO14443_MASK |
NFC_PROTO_ISO14443_B_MASK ) ) {
return nfc_hci_send_cmd ( hdev , target - > hci_reader_gate ,
PN544_RF_READER_CMD_PRESENCE_CHECK ,
NULL , 0 , NULL ) ;
} else if ( target - > supported_protocols & NFC_PROTO_MIFARE_MASK ) {
if ( target - > nfcid1_len ! = 4 & & target - > nfcid1_len ! = 7 & &
target - > nfcid1_len ! = 10 )
2012-10-02 19:27:36 +04:00
return - EOPNOTSUPP ;
2012-09-27 13:32:59 +04:00
return nfc_hci_send_cmd ( hdev , NFC_HCI_RF_READER_A_GATE ,
PN544_RF_READER_CMD_ACTIVATE_NEXT ,
target - > nfcid1 , target - > nfcid1_len , NULL ) ;
2013-04-22 13:21:27 +04:00
} else if ( target - > supported_protocols & ( NFC_PROTO_JEWEL_MASK |
NFC_PROTO_FELICA_MASK ) ) {
return - EOPNOTSUPP ;
2012-09-27 13:32:59 +04:00
} else if ( target - > supported_protocols & NFC_PROTO_NFC_DEP_MASK ) {
return nfc_hci_send_cmd ( hdev , target - > hci_reader_gate ,
PN544_HCI_CMD_ATTREQUEST ,
NULL , 0 , NULL ) ;
}
return 0 ;
2012-05-07 14:31:29 +04:00
}
2012-12-04 19:43:24 +04:00
/*
* Returns :
* < = 0 : driver handled the event , skb consumed
* 1 : driver does not handle the event , please do standard processing
*/
2012-11-28 18:48:44 +04:00
static int pn544_hci_event_received ( struct nfc_hci_dev * hdev , u8 gate , u8 event ,
struct sk_buff * skb )
2012-09-27 13:32:55 +04:00
{
struct sk_buff * rgb_skb = NULL ;
2012-12-04 19:43:24 +04:00
int r ;
2012-09-27 13:32:55 +04:00
pr_debug ( " hci event %d " , event ) ;
switch ( event ) {
case PN544_HCI_EVT_ACTIVATED :
2012-12-04 19:43:24 +04:00
if ( gate = = PN544_RF_READER_NFCIP1_INITIATOR_GATE ) {
2012-11-28 18:48:44 +04:00
r = nfc_hci_target_discovered ( hdev , gate ) ;
2012-12-04 19:43:24 +04:00
} else if ( gate = = PN544_RF_READER_NFCIP1_TARGET_GATE ) {
2012-09-27 13:32:55 +04:00
r = nfc_hci_get_param ( hdev , gate , PN544_DEP_ATR_REQ ,
2012-11-28 18:48:44 +04:00
& rgb_skb ) ;
2012-09-27 13:32:55 +04:00
if ( r < 0 )
goto exit ;
2012-11-28 18:48:44 +04:00
r = nfc_tm_activated ( hdev - > ndev , NFC_PROTO_NFC_DEP_MASK ,
NFC_COMM_PASSIVE , rgb_skb - > data ,
rgb_skb - > len ) ;
2012-09-27 13:32:55 +04:00
kfree_skb ( rgb_skb ) ;
2012-12-04 19:43:24 +04:00
} else {
r = - EINVAL ;
2012-09-27 13:32:55 +04:00
}
break ;
case PN544_HCI_EVT_DEACTIVATED :
2012-11-28 18:48:44 +04:00
r = nfc_hci_send_event ( hdev , gate , NFC_HCI_EVT_END_OPERATION ,
NULL , 0 ) ;
2012-09-27 13:32:55 +04:00
break ;
2012-09-27 13:32:58 +04:00
case PN544_HCI_EVT_RCV_DATA :
if ( skb - > len < 2 ) {
r = - EPROTO ;
goto exit ;
}
if ( skb - > data [ 0 ] ! = 0 ) {
pr_debug ( " data0 %d " , skb - > data [ 0 ] ) ;
r = - EPROTO ;
goto exit ;
}
skb_pull ( skb , 2 ) ;
2012-11-28 18:48:44 +04:00
return nfc_tm_data_received ( hdev - > ndev , skb ) ;
2012-09-27 13:32:55 +04:00
default :
2012-12-04 19:43:24 +04:00
return 1 ;
2012-09-27 13:32:55 +04:00
}
exit :
kfree_skb ( skb ) ;
2012-11-28 18:48:44 +04:00
return r ;
2012-09-27 13:32:55 +04:00
}
2012-09-18 21:45:48 +04:00
static struct nfc_hci_ops pn544_hci_ops = {
2012-05-07 14:31:29 +04:00
. open = pn544_hci_open ,
. close = pn544_hci_close ,
. hci_ready = pn544_hci_ready ,
. xmit = pn544_hci_xmit ,
. start_poll = pn544_hci_start_poll ,
2012-09-27 13:32:57 +04:00
. dep_link_up = pn544_hci_dep_link_up ,
. dep_link_down = pn544_hci_dep_link_down ,
2012-05-07 14:31:29 +04:00
. target_from_gate = pn544_hci_target_from_gate ,
. complete_target_discovered = pn544_hci_complete_target_discovered ,
2012-09-27 13:32:58 +04:00
. im_transceive = pn544_hci_im_transceive ,
. tm_send = pn544_hci_tm_send ,
2012-05-07 14:31:29 +04:00
. check_presence = pn544_hci_check_presence ,
2012-09-27 13:32:55 +04:00
. event_received = pn544_hci_event_received ,
2012-05-07 14:31:29 +04:00
} ;
2012-10-02 20:44:06 +04:00
int pn544_hci_probe ( void * phy_id , struct nfc_phy_ops * phy_ops , char * llc_name ,
int phy_headroom , int phy_tailroom , int phy_payload ,
struct nfc_hci_dev * * hdev )
2012-05-07 14:31:29 +04:00
{
struct pn544_hci_info * info ;
2012-12-19 22:11:32 +04:00
u32 protocols , se ;
2012-05-07 14:31:29 +04:00
struct nfc_hci_init_data init_data ;
2012-10-02 20:44:06 +04:00
int r ;
2012-05-07 14:31:29 +04:00
info = kzalloc ( sizeof ( struct pn544_hci_info ) , GFP_KERNEL ) ;
if ( ! info ) {
2012-10-02 20:44:06 +04:00
pr_err ( " Cannot allocate memory for pn544_hci_info. \n " ) ;
2012-05-07 14:31:29 +04:00
r = - ENOMEM ;
goto err_info_alloc ;
}
2012-10-02 20:44:06 +04:00
info - > phy_ops = phy_ops ;
info - > phy_id = phy_id ;
2012-05-07 14:31:29 +04:00
info - > state = PN544_ST_COLD ;
mutex_init ( & info - > info_lock ) ;
2012-06-05 16:42:11 +04:00
init_data . gate_count = ARRAY_SIZE ( pn544_gates ) ;
2012-05-07 14:31:29 +04:00
2012-06-05 16:42:11 +04:00
memcpy ( init_data . gates , pn544_gates , sizeof ( pn544_gates ) ) ;
2012-05-07 14:31:29 +04:00
/*
* TODO : Session id must include the driver name + some bus addr
* persistent info to discriminate 2 identical chips
*/
strcpy ( init_data . session_id , " ID544HCI " ) ;
protocols = NFC_PROTO_JEWEL_MASK |
NFC_PROTO_MIFARE_MASK |
NFC_PROTO_FELICA_MASK |
NFC_PROTO_ISO14443_MASK |
2012-07-04 02:14:04 +04:00
NFC_PROTO_ISO14443_B_MASK |
2012-05-07 14:31:29 +04:00
NFC_PROTO_NFC_DEP_MASK ;
2012-12-19 22:11:32 +04:00
se = NFC_SE_UICC | NFC_SE_EMBEDDED ;
2012-12-18 17:15:49 +04:00
info - > hdev = nfc_hci_allocate_device ( & pn544_hci_ops , & init_data , 0 ,
2012-12-19 22:11:32 +04:00
protocols , se , llc_name ,
2012-10-02 20:44:06 +04:00
phy_headroom + PN544_CMDS_HEADROOM ,
phy_tailroom , phy_payload ) ;
2012-09-18 21:45:48 +04:00
if ( ! info - > hdev ) {
2012-10-02 20:44:06 +04:00
pr_err ( " Cannot allocate nfc hdev. \n " ) ;
2012-05-07 14:31:29 +04:00
r = - ENOMEM ;
2012-09-18 21:45:48 +04:00
goto err_alloc_hdev ;
2012-05-07 14:31:29 +04:00
}
2012-09-18 21:45:48 +04:00
nfc_hci_set_clientdata ( info - > hdev , info ) ;
r = nfc_hci_register_device ( info - > hdev ) ;
if ( r )
goto err_regdev ;
2012-05-07 14:31:29 +04:00
2012-10-02 20:44:06 +04:00
* hdev = info - > hdev ;
2012-05-07 14:31:29 +04:00
return 0 ;
2012-09-18 21:45:48 +04:00
err_regdev :
nfc_hci_free_device ( info - > hdev ) ;
err_alloc_hdev :
2012-05-07 14:31:29 +04:00
kfree ( info ) ;
err_info_alloc :
return r ;
}
2012-12-18 19:26:23 +04:00
EXPORT_SYMBOL ( pn544_hci_probe ) ;
2012-05-07 14:31:29 +04:00
2012-10-02 20:44:06 +04:00
void pn544_hci_remove ( struct nfc_hci_dev * hdev )
2012-05-07 14:31:29 +04:00
{
2012-10-02 20:44:06 +04:00
struct pn544_hci_info * info = nfc_hci_get_clientdata ( hdev ) ;
2012-05-07 14:31:29 +04:00
2012-10-02 20:44:06 +04:00
nfc_hci_unregister_device ( hdev ) ;
nfc_hci_free_device ( hdev ) ;
2012-05-07 14:31:29 +04:00
kfree ( info ) ;
}
2012-12-18 19:26:23 +04:00
EXPORT_SYMBOL ( pn544_hci_remove ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;