2011-07-02 02:31:34 +04:00
/*
* Copyright ( C ) 2011 Instituto Nokia de Tecnologia
*
* Authors :
* Lauro Ramos Venancio < lauro . venancio @ openbossa . org >
* Aloisio Almeida Jr < aloisio . almeida @ openbossa . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*/
2011-12-14 19:43:05 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
2011-11-29 23:37:33 +04:00
2011-07-02 02:31:34 +04:00
# include <net/genetlink.h>
# include <linux/nfc.h>
# include <linux/slab.h>
# include "nfc.h"
static struct genl_multicast_group nfc_genl_event_mcgrp = {
. name = NFC_GENL_MCAST_EVENT_NAME ,
} ;
2012-05-07 14:31:28 +04:00
static struct genl_family nfc_genl_family = {
2011-07-02 02:31:34 +04:00
. id = GENL_ID_GENERATE ,
. hdrsize = 0 ,
. name = NFC_GENL_NAME ,
. version = NFC_GENL_VERSION ,
. maxattr = NFC_ATTR_MAX ,
} ;
static const struct nla_policy nfc_genl_policy [ NFC_ATTR_MAX + 1 ] = {
[ NFC_ATTR_DEVICE_INDEX ] = { . type = NLA_U32 } ,
[ NFC_ATTR_DEVICE_NAME ] = { . type = NLA_STRING ,
. len = NFC_DEVICE_NAME_MAXSIZE } ,
[ NFC_ATTR_PROTOCOLS ] = { . type = NLA_U32 } ,
2011-12-14 19:43:09 +04:00
[ NFC_ATTR_COMM_MODE ] = { . type = NLA_U8 } ,
[ NFC_ATTR_RF_MODE ] = { . type = NLA_U8 } ,
2012-03-05 04:03:34 +04:00
[ NFC_ATTR_DEVICE_POWERED ] = { . type = NLA_U8 } ,
2012-05-15 17:57:06 +04:00
[ NFC_ATTR_IM_PROTOCOLS ] = { . type = NLA_U32 } ,
[ NFC_ATTR_TM_PROTOCOLS ] = { . type = NLA_U32 } ,
2011-07-02 02:31:34 +04:00
} ;
static int nfc_genl_send_target ( struct sk_buff * msg , struct nfc_target * target ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb , int flags )
2011-07-02 02:31:34 +04:00
{
void * hdr ;
hdr = genlmsg_put ( msg , NETLINK_CB ( cb - > skb ) . pid , cb - > nlh - > nlmsg_seq ,
2012-03-05 04:03:53 +04:00
& nfc_genl_family , flags , NFC_CMD_GET_TARGET ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
return - EMSGSIZE ;
genl_dump_check_consistent ( cb , hdr , & nfc_genl_family ) ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , target - > supported_protocols ) | |
nla_put_u16 ( msg , NFC_ATTR_TARGET_SENS_RES , target - > sens_res ) | |
nla_put_u8 ( msg , NFC_ATTR_TARGET_SEL_RES , target - > sel_res ) )
goto nla_put_failure ;
if ( target - > nfcid1_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_NFCID1 , target - > nfcid1_len ,
target - > nfcid1 ) )
goto nla_put_failure ;
if ( target - > sensb_res_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_SENSB_RES , target - > sensb_res_len ,
target - > sensb_res ) )
goto nla_put_failure ;
if ( target - > sensf_res_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_SENSF_RES , target - > sensf_res_len ,
target - > sensf_res ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
return genlmsg_end ( msg , hdr ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static struct nfc_dev * __get_device_from_cb ( struct netlink_callback * cb )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
rc = nlmsg_parse ( cb - > nlh , GENL_HDRLEN + nfc_genl_family . hdrsize ,
2012-03-05 04:03:53 +04:00
nfc_genl_family . attrbuf ,
nfc_genl_family . maxattr ,
nfc_genl_policy ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
return ERR_PTR ( rc ) ;
if ( ! nfc_genl_family . attrbuf [ NFC_ATTR_DEVICE_INDEX ] )
return ERR_PTR ( - EINVAL ) ;
idx = nla_get_u32 ( nfc_genl_family . attrbuf [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return ERR_PTR ( - ENODEV ) ;
return dev ;
}
static int nfc_genl_dump_targets ( struct sk_buff * skb ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb )
2011-07-02 02:31:34 +04:00
{
int i = cb - > args [ 0 ] ;
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
int rc ;
if ( ! dev ) {
dev = __get_device_from_cb ( cb ) ;
if ( IS_ERR ( dev ) )
return PTR_ERR ( dev ) ;
cb - > args [ 1 ] = ( long ) dev ;
}
2012-05-07 14:31:15 +04:00
device_lock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
cb - > seq = dev - > targets_generation ;
while ( i < dev - > n_targets ) {
rc = nfc_genl_send_target ( skb , & dev - > targets [ i ] , cb ,
2012-03-05 04:03:53 +04:00
NLM_F_MULTI ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
break ;
i + + ;
}
2012-05-07 14:31:15 +04:00
device_unlock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
cb - > args [ 0 ] = i ;
return skb - > len ;
}
static int nfc_genl_dump_targets_done ( struct netlink_callback * cb )
{
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
if ( dev )
nfc_put_device ( dev ) ;
return 0 ;
}
int nfc_genl_targets_found ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
dev - > genl_data . poll_req_pid = 0 ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_ATOMIC ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_TARGETS_FOUND ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
return genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_ATOMIC ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2012-04-10 21:43:04 +04:00
int nfc_genl_target_lost ( struct nfc_dev * dev , u32 target_idx )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_TARGET_LOST ) ;
if ( ! hdr )
goto free_msg ;
2012-04-18 22:17:13 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target_idx ) )
goto nla_put_failure ;
2012-04-10 21:43:04 +04:00
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_KERNEL ) ;
return 0 ;
2012-06-01 15:21:13 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_tm_activated ( struct nfc_dev * dev , u32 protocol )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_TM_ACTIVATED ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , NFC_ATTR_TM_PROTOCOLS , protocol ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_KERNEL ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_tm_deactivated ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_TM_DEACTIVATED ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_KERNEL ) ;
return 0 ;
2012-04-10 21:43:04 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2011-07-02 02:31:34 +04:00
int nfc_genl_device_added ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_DEVICE_ADDED ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , dev - > supported_protocols ) | |
nla_put_u8 ( msg , NFC_ATTR_DEVICE_POWERED , dev - > dev_up ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_KERNEL ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_device_removed ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_DEVICE_REMOVED ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_KERNEL ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
static int nfc_genl_send_device ( struct sk_buff * msg , struct nfc_dev * dev ,
2012-03-05 04:03:53 +04:00
u32 pid , u32 seq ,
struct netlink_callback * cb ,
int flags )
2011-07-02 02:31:34 +04:00
{
void * hdr ;
hdr = genlmsg_put ( msg , pid , seq , & nfc_genl_family , flags ,
2012-03-05 04:03:53 +04:00
NFC_CMD_GET_DEVICE ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
return - EMSGSIZE ;
if ( cb )
genl_dump_check_consistent ( cb , hdr , & nfc_genl_family ) ;
2012-03-30 07:23:57 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , dev - > supported_protocols ) | |
nla_put_u8 ( msg , NFC_ATTR_DEVICE_POWERED , dev - > dev_up ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
return genlmsg_end ( msg , hdr ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int nfc_genl_dump_devices ( struct sk_buff * skb ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb )
2011-07-02 02:31:34 +04:00
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
bool first_call = false ;
if ( ! iter ) {
first_call = true ;
iter = kmalloc ( sizeof ( struct class_dev_iter ) , GFP_KERNEL ) ;
if ( ! iter )
return - ENOMEM ;
cb - > args [ 0 ] = ( long ) iter ;
}
mutex_lock ( & nfc_devlist_mutex ) ;
cb - > seq = nfc_devlist_generation ;
if ( first_call ) {
nfc_device_iter_init ( iter ) ;
dev = nfc_device_iter_next ( iter ) ;
}
while ( dev ) {
int rc ;
rc = nfc_genl_send_device ( skb , dev , NETLINK_CB ( cb - > skb ) . pid ,
2012-03-05 04:03:53 +04:00
cb - > nlh - > nlmsg_seq , cb , NLM_F_MULTI ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
break ;
dev = nfc_device_iter_next ( iter ) ;
}
mutex_unlock ( & nfc_devlist_mutex ) ;
cb - > args [ 1 ] = ( long ) dev ;
return skb - > len ;
}
static int nfc_genl_dump_devices_done ( struct netlink_callback * cb )
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
nfc_device_iter_exit ( iter ) ;
kfree ( iter ) ;
return 0 ;
}
2011-12-14 19:43:09 +04:00
int nfc_genl_dep_link_up_event ( struct nfc_dev * dev , u32 target_idx ,
2012-03-05 04:03:53 +04:00
u8 comm_mode , u8 rf_mode )
2011-12-14 19:43:09 +04:00
{
struct sk_buff * msg ;
void * hdr ;
pr_debug ( " DEP link is up \n " ) ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_ATOMIC ) ;
if ( ! msg )
return - ENOMEM ;
2012-03-05 04:03:53 +04:00
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 , NFC_CMD_DEP_LINK_UP ) ;
2011-12-14 19:43:09 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
if ( rf_mode = = NFC_RF_INITIATOR & &
nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target_idx ) )
goto nla_put_failure ;
if ( nla_put_u8 ( msg , NFC_ATTR_COMM_MODE , comm_mode ) | |
nla_put_u8 ( msg , NFC_ATTR_RF_MODE , rf_mode ) )
goto nla_put_failure ;
2011-12-14 19:43:09 +04:00
genlmsg_end ( msg , hdr ) ;
dev - > dep_link_up = true ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_ATOMIC ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_dep_link_down_event ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
pr_debug ( " DEP link is down \n " ) ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_ATOMIC ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_CMD_DEP_LINK_DOWN ) ;
2011-12-14 19:43:09 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-12-14 19:43:09 +04:00
genlmsg_end ( msg , hdr ) ;
genlmsg_multicast ( msg , 0 , nfc_genl_event_mcgrp . id , GFP_ATOMIC ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2011-07-02 02:31:34 +04:00
static int nfc_genl_get_device ( struct sk_buff * skb , struct genl_info * info )
{
struct sk_buff * msg ;
struct nfc_dev * dev ;
u32 idx ;
int rc = - ENOBUFS ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
msg = nlmsg_new ( NLMSG_GOODSIZE , GFP_KERNEL ) ;
if ( ! msg ) {
rc = - ENOMEM ;
goto out_putdev ;
}
rc = nfc_genl_send_device ( msg , dev , info - > snd_pid , info - > snd_seq ,
2012-03-05 04:03:53 +04:00
NULL , 0 ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
goto out_free ;
nfc_put_device ( dev ) ;
return genlmsg_reply ( msg , info ) ;
out_free :
nlmsg_free ( msg ) ;
out_putdev :
nfc_put_device ( dev ) ;
return rc ;
}
2011-09-18 12:19:33 +04:00
static int nfc_genl_dev_up ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dev_up ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_dev_down ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dev_down ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2011-07-02 02:31:34 +04:00
static int nfc_genl_start_poll ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
2012-05-15 17:57:06 +04:00
u32 im_protocols = 0 , tm_protocols = 0 ;
2011-07-02 02:31:34 +04:00
2011-12-14 19:43:09 +04:00
pr_debug ( " Poll start \n " ) ;
2011-07-02 02:31:34 +04:00
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
2012-05-15 17:57:06 +04:00
( ( ! info - > attrs [ NFC_ATTR_IM_PROTOCOLS ] & &
! info - > attrs [ NFC_ATTR_PROTOCOLS ] ) & &
! info - > attrs [ NFC_ATTR_TM_PROTOCOLS ] ) )
2011-07-02 02:31:34 +04:00
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
2012-05-15 17:57:06 +04:00
if ( info - > attrs [ NFC_ATTR_TM_PROTOCOLS ] )
tm_protocols = nla_get_u32 ( info - > attrs [ NFC_ATTR_TM_PROTOCOLS ] ) ;
else if ( info - > attrs [ NFC_ATTR_PROTOCOLS ] )
tm_protocols = nla_get_u32 ( info - > attrs [ NFC_ATTR_PROTOCOLS ] ) ;
if ( info - > attrs [ NFC_ATTR_IM_PROTOCOLS ] )
im_protocols = nla_get_u32 ( info - > attrs [ NFC_ATTR_IM_PROTOCOLS ] ) ;
2011-07-02 02:31:34 +04:00
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > genl_data . genl_data_mutex ) ;
2012-05-15 17:57:06 +04:00
rc = nfc_start_poll ( dev , im_protocols , tm_protocols ) ;
2011-07-02 02:31:34 +04:00
if ( ! rc )
dev - > genl_data . poll_req_pid = info - > snd_pid ;
mutex_unlock ( & dev - > genl_data . genl_data_mutex ) ;
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_stop_poll ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > genl_data . genl_data_mutex ) ;
if ( dev - > genl_data . poll_req_pid ! = info - > snd_pid ) {
rc = - EBUSY ;
goto out ;
}
rc = nfc_stop_poll ( dev ) ;
dev - > genl_data . poll_req_pid = 0 ;
out :
mutex_unlock ( & dev - > genl_data . genl_data_mutex ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2011-12-14 19:43:09 +04:00
static int nfc_genl_dep_link_up ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc , tgt_idx ;
u32 idx ;
2012-03-05 04:03:50 +04:00
u8 comm ;
2011-12-14 19:43:09 +04:00
pr_debug ( " DEP link up \n " ) ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
2012-03-05 04:03:50 +04:00
! info - > attrs [ NFC_ATTR_COMM_MODE ] )
2011-12-14 19:43:09 +04:00
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
if ( ! info - > attrs [ NFC_ATTR_TARGET_INDEX ] )
tgt_idx = NFC_TARGET_IDX_ANY ;
else
tgt_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_TARGET_INDEX ] ) ;
comm = nla_get_u8 ( info - > attrs [ NFC_ATTR_COMM_MODE ] ) ;
if ( comm ! = NFC_COMM_ACTIVE & & comm ! = NFC_COMM_PASSIVE )
return - EINVAL ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
2012-03-05 04:03:50 +04:00
rc = nfc_dep_link_up ( dev , tgt_idx , comm ) ;
2011-12-14 19:43:09 +04:00
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_dep_link_down ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dep_link_down ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2011-07-02 02:31:34 +04:00
static struct genl_ops nfc_genl_ops [ ] = {
{
. cmd = NFC_CMD_GET_DEVICE ,
. doit = nfc_genl_get_device ,
. dumpit = nfc_genl_dump_devices ,
. done = nfc_genl_dump_devices_done ,
. policy = nfc_genl_policy ,
2011-09-18 12:19:33 +04:00
} ,
{
. cmd = NFC_CMD_DEV_UP ,
. doit = nfc_genl_dev_up ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_DEV_DOWN ,
. doit = nfc_genl_dev_down ,
. policy = nfc_genl_policy ,
2011-07-02 02:31:34 +04:00
} ,
{
. cmd = NFC_CMD_START_POLL ,
. doit = nfc_genl_start_poll ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_STOP_POLL ,
. doit = nfc_genl_stop_poll ,
. policy = nfc_genl_policy ,
} ,
2011-12-14 19:43:09 +04:00
{
. cmd = NFC_CMD_DEP_LINK_UP ,
. doit = nfc_genl_dep_link_up ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_DEP_LINK_DOWN ,
. doit = nfc_genl_dep_link_down ,
. policy = nfc_genl_policy ,
} ,
2011-07-02 02:31:34 +04:00
{
. cmd = NFC_CMD_GET_TARGET ,
. dumpit = nfc_genl_dump_targets ,
. done = nfc_genl_dump_targets_done ,
. policy = nfc_genl_policy ,
} ,
} ;
static int nfc_genl_rcv_nl_event ( struct notifier_block * this ,
2012-03-05 04:03:53 +04:00
unsigned long event , void * ptr )
2011-07-02 02:31:34 +04:00
{
struct netlink_notify * n = ptr ;
struct class_dev_iter iter ;
struct nfc_dev * dev ;
if ( event ! = NETLINK_URELEASE | | n - > protocol ! = NETLINK_GENERIC )
goto out ;
2011-11-29 23:37:33 +04:00
pr_debug ( " NETLINK_URELEASE event from id %d \n " , n - > pid ) ;
2011-07-02 02:31:34 +04:00
nfc_device_iter_init ( & iter ) ;
dev = nfc_device_iter_next ( & iter ) ;
while ( dev ) {
if ( dev - > genl_data . poll_req_pid = = n - > pid ) {
nfc_stop_poll ( dev ) ;
dev - > genl_data . poll_req_pid = 0 ;
}
dev = nfc_device_iter_next ( & iter ) ;
}
nfc_device_iter_exit ( & iter ) ;
out :
return NOTIFY_DONE ;
}
void nfc_genl_data_init ( struct nfc_genl_data * genl_data )
{
genl_data - > poll_req_pid = 0 ;
mutex_init ( & genl_data - > genl_data_mutex ) ;
}
void nfc_genl_data_exit ( struct nfc_genl_data * genl_data )
{
mutex_destroy ( & genl_data - > genl_data_mutex ) ;
}
static struct notifier_block nl_notifier = {
. notifier_call = nfc_genl_rcv_nl_event ,
} ;
/**
* nfc_genl_init ( ) - Initialize netlink interface
*
* This initialization function registers the nfc netlink family .
*/
int __init nfc_genl_init ( void )
{
int rc ;
rc = genl_register_family_with_ops ( & nfc_genl_family , nfc_genl_ops ,
2012-03-05 04:03:53 +04:00
ARRAY_SIZE ( nfc_genl_ops ) ) ;
2011-07-02 02:31:34 +04:00
if ( rc )
return rc ;
rc = genl_register_mc_group ( & nfc_genl_family , & nfc_genl_event_mcgrp ) ;
netlink_register_notifier ( & nl_notifier ) ;
return rc ;
}
/**
* nfc_genl_exit ( ) - Deinitialize netlink interface
*
* This exit function unregisters the nfc netlink family .
*/
void nfc_genl_exit ( void )
{
netlink_unregister_notifier ( & nl_notifier ) ;
genl_unregister_family ( & nfc_genl_family ) ;
}