From: "Gustavo F. Padovan" <padovan@profusion.mobi>
To: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org,
sameo@linux.intel.com, johannes@sipsolutions.net,
lauro.venancio@openbossa.org, marcio.macedo@openbossa.org,
Waldemar.Rymarkiewicz@tieto.com
Subject: Re: [RFC][PATCH v2 3/7] NFC: add nfc generic netlink interface
Date: Tue, 21 Jun 2011 19:05:10 -0300 [thread overview]
Message-ID: <20110621220510.GG2628@joana> (raw)
In-Reply-To: <1308592212-5755-4-git-send-email-aloisio.almeida@openbossa.org>
* Aloisio Almeida Jr <aloisio.almeida@openbossa.org> [2011-06-20 14:50:08 -0300]:
> From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
>
> The NFC generic netlink interface exports the NFC control operations
> to the user space.
>
> Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
> Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> ---
> include/linux/nfc.h | 111 +++++++++++
> include/net/nfc.h | 21 ++
> net/nfc/Makefile | 2 +-
> net/nfc/core.c | 83 ++++++++-
> net/nfc/netlink.c | 537 +++++++++++++++++++++++++++++++++++++++++++++++++++
> net/nfc/nfc.h | 11 +
> 6 files changed, 762 insertions(+), 3 deletions(-)
> create mode 100644 include/linux/nfc.h
> create mode 100644 net/nfc/netlink.c
>
> diff --git a/include/linux/nfc.h b/include/linux/nfc.h
> new file mode 100644
> index 0000000..59b3c79
> --- /dev/null
> +++ b/include/linux/nfc.h
> @@ -0,0 +1,111 @@
> +/*
> + * 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.
> + */
> +
> +#ifndef __LINUX_NFC_H
> +#define __LINUX_NFC_H
> +
> +#define NFC_GENL_NAME "nfc"
> +#define NFC_GENL_VERSION 1
> +
> +#define NFC_GENL_MCAST_EVENT_NAME "events"
> +
> +/**
> + * enum nfc_commands - supported nfc commands
> + *
> + * @NFC_CMD_UNSPEC: unspecified command
> + *
> + * @NFC_CMD_GET_DEVICE: request information about a device (requires
> + * %NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
> + * @NFC_CMD_START_POLL: start polling for targets using the given protocols
> + * (requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
> + * @NFC_CMD_STOP_POLL: stop polling for targets (requires
> + * %NFC_ATTR_DEVICE_INDEX)
> + * @NFC_CMD_GET_TARGET: dump all targets found by the previous poll (requires
> + * %NFC_ATTR_DEVICE_INDEX)
> + * @NFC_EVENT_TARGETS_FOUND: event emitted when a new target is found
> + * (it sends %NFC_ATTR_DEVICE_INDEX)
> + * @NFC_EVENT_DEVICE_ADDED: event emitted when a new device is registred
> + * (it sends %NFC_ATTR_DEVICE_NAME, %NFC_ATTR_DEVICE_INDEX and
> + * %NFC_ATTR_PROTOCOLS)
> + * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
> + * (it sends %NFC_ATTR_DEVICE_INDEX)
> + */
> +enum nfc_commands {
> + NFC_CMD_UNSPEC,
> + NFC_CMD_GET_DEVICE,
> + NFC_CMD_START_POLL,
> + NFC_CMD_STOP_POLL,
> + NFC_CMD_GET_TARGET,
> + NFC_EVENT_TARGETS_FOUND,
> + NFC_EVENT_DEVICE_ADDED,
> + NFC_EVENT_DEVICE_REMOVED,
> +/* private: internal use only */
> + __NFC_CMD_AFTER_LAST
> +};
> +#define NFC_CMD_MAX (__NFC_CMD_AFTER_LAST - 1)
> +
> +/**
> + * enum nfc_attrs - supported nfc attributes
> + *
> + * @NFC_ATTR_UNSPEC: unspecified attribute
> + *
> + * @NFC_ATTR_DEVICE_INDEX: index of nfc device
> + * @NFC_ATTR_DEVICE_NAME: device name, max 8 chars
> + * @NFC_ATTR_PROTOCOLS: nfc protocols - bitwise or-ed combination from
> + * NFC_PROTO_*_MASK constants
> + * @NFC_ATTR_TARGET_INDEX: index of the nfc target
> + * @NFC_ATTR_TARGET_SENS_RES: extra information for NFC-A targets
> + * @NFC_ATTR_TARGET_SEL_RES: extra information for NFC-A targets
> + */
> +enum nfc_attrs {
> + NFC_ATTR_UNSPEC,
> + NFC_ATTR_DEVICE_INDEX,
> + NFC_ATTR_DEVICE_NAME,
> + NFC_ATTR_PROTOCOLS,
> + NFC_ATTR_TARGET_INDEX,
> + NFC_ATTR_TARGET_SENS_RES,
> + NFC_ATTR_TARGET_SEL_RES,
> +/* private: internal use only */
> + __NFC_ATTR_AFTER_LAST
> +};
> +#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
> +
> +#define NFC_DEVICE_NAME_MAXSIZE 8
> +
> +/* NFC protocols */
> +#define NFC_PROTO_JEWEL 0
> +#define NFC_PROTO_MIFARE 1
> +#define NFC_PROTO_FELICA 2
> +#define NFC_PROTO_ISO14443 3
> +#define NFC_PROTO_NFC_DEP 4
> +
> +#define NFC_PROTO_MAX 5
> +
> +/* NFC protocols masks used in bitsets */
> +#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL)
> +#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE)
> +#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA)
> +#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443)
> +#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP)
> +
> +#endif /*__LINUX_NFC_H */
> diff --git a/include/net/nfc.h b/include/net/nfc.h
> index 11d63dc..01a30b3 100644
> --- a/include/net/nfc.h
> +++ b/include/net/nfc.h
> @@ -54,10 +54,28 @@ struct nfc_ops {
> void *cb_context);
> };
>
> +struct nfc_target {
> + u32 idx;
> + u32 supported_protocols;
> + u16 sens_res;
> + u8 sel_res;
> +};
> +
> +struct nfc_genl_data {
> + u32 poll_req_pid;
> + struct mutex genl_data_mutex;
> +};
> +
> struct nfc_dev {
> unsigned idx;
> + unsigned target_idx;
> + struct nfc_target *targets;
> + int n_targets;
> + int targets_generation;
> + spinlock_t targets_lock;
> struct device dev;
> bool polling;
> + struct nfc_genl_data genl_data;
> u32 supported_protocols;
>
> struct nfc_ops *ops;
> @@ -128,4 +146,7 @@ static inline const char *nfc_device_name(struct nfc_dev *dev)
>
> struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp);
>
> +int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
> + int ntargets);
> +
> #endif /* __NET_NFC_H */
> diff --git a/net/nfc/Makefile b/net/nfc/Makefile
> index d837743..8aeaddc 100644
> --- a/net/nfc/Makefile
> +++ b/net/nfc/Makefile
> @@ -4,6 +4,6 @@
>
> obj-$(CONFIG_NFC) += nfc.o
>
> -nfc-objs := core.o
> +nfc-objs := core.o netlink.o
>
> ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
> diff --git a/net/nfc/core.c b/net/nfc/core.c
> index f4710fe..5e09d50 100644
> --- a/net/nfc/core.c
> +++ b/net/nfc/core.c
> @@ -213,12 +213,61 @@ struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp)
> }
> EXPORT_SYMBOL(nfc_alloc_skb);
>
> +/**
> + * nfc_targets_found - inform that targets were found
> + *
> + * @dev: The nfc device that found the targets
> + * @targets: array of nfc targets found
> + * @ntargets: targets array size
> + *
> + * The device driver must call this function when one or many nfc targets
> + * are found. After calling this function, the device driver must stop
> + * polling for targets.
> + */
> +int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
> + int n_targets)
> +{
> + int i;
> +
> + pr_debug("%s: dev_name:%s", __func__, dev_name(&dev->dev));
> +
> + dev->polling = false;
> +
> + for (i = 0; i < n_targets; i++)
> + targets[i].idx = dev->target_idx++;
> +
> + spin_lock_bh(&dev->targets_lock);
> +
> + dev->targets_generation++;
> +
> + kfree(dev->targets);
> + dev->targets = kzalloc(n_targets * sizeof(struct nfc_target),
> + GFP_ATOMIC);
> + if (!dev->targets) {
> + dev->n_targets = 0;
> + spin_unlock_bh(&dev->targets_lock);
> + return -ENOMEM;
> + }
> +
> + memcpy(dev->targets, targets, n_targets * sizeof(struct nfc_target));
> + dev->n_targets = n_targets;
> +
> + spin_unlock_bh(&dev->targets_lock);
> +
> + nfc_genl_targets_found(dev);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(nfc_targets_found);
> +
> static void nfc_release(struct device *d)
> {
> struct nfc_dev *dev = to_nfc_dev(d);
>
> pr_debug("%s: dev_name:%s", __func__, dev_name(&dev->dev));
>
> + nfc_genl_data_exit(&dev->genl_data);
> + kfree(dev->targets);
> kfree(dev);
> }
>
> @@ -278,6 +327,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
> dev->ops = ops;
> dev->supported_protocols = supported_protocols;
>
> + spin_lock_init(&dev->targets_lock);
> + nfc_genl_data_init(&dev->genl_data);
> +
> + /* first generation must not be 0 */
> + dev->targets_generation = 1;
> +
> return dev;
> }
> EXPORT_SYMBOL(nfc_allocate_device);
> @@ -298,7 +353,10 @@ int nfc_register_device(struct nfc_dev *dev)
> rc = device_add(&dev->dev);
> mutex_unlock(&nfc_devlist_mutex);
>
> - return rc;
> + if (rc < 0)
> + return rc;
> +
> + return nfc_genl_device_added(dev);
> }
> EXPORT_SYMBOL(nfc_register_device);
>
> @@ -321,18 +379,39 @@ void nfc_unregister_device(struct nfc_dev *dev)
> device_unlock(&dev->dev);
>
> mutex_unlock(&nfc_devlist_mutex);
> +
> + nfc_genl_device_removed(dev);
> }
> EXPORT_SYMBOL(nfc_unregister_device);
>
> static int __init nfc_init(void)
> {
> + int rc;
> +
> printk(KERN_INFO "NFC Core ver %s\n", VERSION);
>
> - return class_register(&nfc_class);
> + rc = class_register(&nfc_class);
> + if (rc)
> + goto err;
Just return rc here and get rid of the label.
> +
> + rc = nfc_genl_init();
> + if (rc)
> + goto err_genl;
> +
> + /* the first generation must not be 0 */
> + nfc_devlist_generation = 1;
> +
> + return 0;
> +
> +err_genl:
> + class_unregister(&nfc_class);
> +err:
> + return rc;
> }
>
> static void __exit nfc_exit(void)
> {
> + nfc_genl_exit();
> class_unregister(&nfc_class);
> }
>
> diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
> new file mode 100644
> index 0000000..5f2ddb2
> --- /dev/null
> +++ b/net/nfc/netlink.c
> @@ -0,0 +1,537 @@
> +/*
> + * 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.
> + */
> +
> +#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,
> +};
> +
> +struct genl_family nfc_genl_family = {
> + .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 },
> +};
> +
> +static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
> + struct netlink_callback *cb, int flags)
> +{
> + void *hdr;
> +
> + pr_debug("%s\n", __func__);
> +
> + hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
> + &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
> + if (!hdr)
> + return -EMSGSIZE;
> +
> + genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
> +
> + 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);
> +
> + return genlmsg_end(msg, hdr);
> +
> +nla_put_failure:
There is no use for this macro in all function that have a label with this
name.
> + 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,
> + nfc_genl_family.attrbuf,
> + nfc_genl_family.maxattr,
> + nfc_genl_policy);
> + 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,
> + struct netlink_callback *cb)
> +{
> + int i = cb->args[0];
> + struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
> + int rc;
> +
> + pr_debug("%s\n", __func__);
> +
> + if (!dev) {
> + dev = __get_device_from_cb(cb);
> + if (IS_ERR(dev))
> + return PTR_ERR(dev);
> +
> + cb->args[1] = (long) dev;
> + }
> +
> + spin_lock_bh(&dev->targets_lock);
> +
> + cb->seq = dev->targets_generation;
> +
> + while (i < dev->n_targets) {
> + rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
> + NLM_F_MULTI);
> + if (rc < 0)
> + break;
> +
> + i++;
> + }
> +
> + spin_unlock_bh(&dev->targets_lock);
> +
> + 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];
> +
> + pr_debug("%s\n", __func__);
> +
> + if (dev)
> + nfc_put_device(dev);
> +
> + return 0;
> +}
> +
> +int nfc_genl_targets_found(struct nfc_dev *dev)
> +{
> + struct sk_buff *msg;
> + void *hdr;
> +
> + pr_debug("%s\n", __func__);
> +
> + 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,
> + NFC_EVENT_TARGETS_FOUND);
> + if (!hdr)
> + goto free_msg;
> +
> + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
> +
> + 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;
> +}
> +
> +int nfc_genl_device_added(struct nfc_dev *dev)
> +{
> + struct sk_buff *msg;
> + void *hdr;
> +
> + pr_debug("%s\n", __func__);
> +
> + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
> + NFC_EVENT_DEVICE_ADDED);
> + if (!hdr)
> + goto free_msg;
> +
> + 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);
> +
> + 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;
> +
> + pr_debug("%s\n", __func__);
> +
> + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
> + NFC_EVENT_DEVICE_REMOVED);
> + if (!hdr)
> + goto free_msg;
> +
> + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
> +
> + 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,
> + u32 pid, u32 seq,
> + struct netlink_callback *cb,
> + int flags)
> +{
> + void *hdr;
> +
> + pr_debug("%s\n", __func__);
> +
> + hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
> + NFC_CMD_GET_DEVICE);
> + if (!hdr)
> + return -EMSGSIZE;
> +
> + if (cb)
> + genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
> +
> + 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);
> +
> + return genlmsg_end(msg, hdr);
> +
> +nla_put_failure:
> + genlmsg_cancel(msg, hdr);
> + return -EMSGSIZE;
> +}
> +
> +static int nfc_genl_dump_devices(struct sk_buff *skb,
> + struct netlink_callback *cb)
> +{
> + 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;
> +
> + pr_debug("%s\n", __func__);
> +
> + 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,
> + cb->nlh->nlmsg_seq,
> + cb, NLM_F_MULTI);
> + 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];
> +
> + pr_debug("%s\n", __func__);
> +
> + nfc_device_iter_exit(iter);
> + kfree(iter);
> +
> + return 0;
> +}
> +
> +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;
> +
> + pr_debug("%s\n", __func__);
> +
> + 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,
> + NULL, 0);
> + 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;
> +}
> +
> +static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct nfc_dev *dev;
> + int rc;
> + u32 idx;
> + u32 protocols;
> +
> + pr_debug("%s\n", __func__);
> +
> + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
> + !info->attrs[NFC_ATTR_PROTOCOLS])
> + return -EINVAL;
> +
> + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
> + protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
> +
> + dev = nfc_get_device(idx);
> + if (!dev)
> + return -ENODEV;
> +
> + mutex_lock(&dev->genl_data.genl_data_mutex);
> +
> + rc = nfc_start_poll(dev, protocols);
> + 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;
> +
> + pr_debug("%s\n", __func__);
> +
> + 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;
> +}
> +
> +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,
> + },
> + {
> + .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,
> + },
> + {
> + .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,
> + unsigned long event, void *ptr)
> +{
> + struct netlink_notify *n = ptr;
> + struct class_dev_iter iter;
> + struct nfc_dev *dev;
> +
> + if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
> + goto out;
> +
> + pr_debug("%s: NETLINK_URELEASE event from id %d\n", __func__, n->pid);
> +
> + nfc_device_iter_init(&iter);
> + dev = nfc_device_iter_next(&iter);
> +
> + while (dev) {
> + mutex_lock(&dev->genl_data.genl_data_mutex);
> + if (dev->genl_data.poll_req_pid == n->pid) {
> + nfc_stop_poll(dev);
> + dev->genl_data.poll_req_pid = 0;
> + }
> + mutex_unlock(&dev->genl_data.genl_data_mutex);
> + 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,
> + ARRAY_SIZE(nfc_genl_ops));
> + 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)
You may want __exit here.
Gustavo
next prev parent reply other threads:[~2011-06-21 22:04 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-20 17:50 [RFC][PATCH v2 0/7] NFC subsystem Aloisio Almeida Jr
2011-06-20 17:50 ` [RFC][PATCH v2 1/7] netlink: advertise incomplete dumps Aloisio Almeida Jr
2011-06-20 17:50 ` [RFC][PATCH v2 2/7] NFC: add nfc subsystem core Aloisio Almeida Jr
2011-06-21 21:55 ` Gustavo F. Padovan
2011-06-22 2:24 ` Marcel Holtmann
2011-06-22 14:18 ` Aloisio Almeida
2011-06-20 17:50 ` [RFC][PATCH v2 3/7] NFC: add nfc generic netlink interface Aloisio Almeida Jr
2011-06-21 22:05 ` Gustavo F. Padovan [this message]
2011-06-21 22:15 ` Eliad Peller
2011-06-22 20:03 ` Gustavo F. Padovan
2011-06-22 6:56 ` Johannes Berg
2011-06-22 19:55 ` Gustavo F. Padovan
2011-06-22 14:07 ` Aloisio Almeida
2011-06-22 7:34 ` Johannes Berg
2011-06-22 12:57 ` Samuel Ortiz
2011-06-22 13:08 ` Johannes Berg
2011-06-22 13:27 ` Samuel Ortiz
2011-06-22 16:49 ` Aloisio Almeida
2011-06-23 7:55 ` Johannes Berg
2011-06-20 17:50 ` [RFC][PATCH v2 4/7] NFC: add NFC socket family Aloisio Almeida Jr
2011-06-20 17:50 ` [RFC][PATCH v2 5/7] NFC: add the NFC socket raw protocol Aloisio Almeida Jr
2011-06-20 17:50 ` [RFC][PATCH v2 6/7] NFC: pn533: add NXP pn533 nfc device driver Aloisio Almeida Jr
2011-06-20 17:50 ` [RFC][PATCH v2 7/7] NFC: add Documentation/networking/nfc.txt Aloisio Almeida Jr
2011-06-20 20:24 ` [RFC][PATCH v3 " Aloisio Almeida Jr
2011-06-21 21:23 ` Randy Dunlap
2011-06-22 14:13 ` Aloisio Almeida
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110621220510.GG2628@joana \
--to=padovan@profusion.mobi \
--cc=Waldemar.Rymarkiewicz@tieto.com \
--cc=aloisio.almeida@openbossa.org \
--cc=johannes@sipsolutions.net \
--cc=lauro.venancio@openbossa.org \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=marcio.macedo@openbossa.org \
--cc=sameo@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).