This is the 2nd NFC pull request for 3.10.
With this one we have: - A major pn533 update. The pn533 framing support has been changed in order to easily support all pn533 derivatives. For example we now support the ACR122 USB dongle. - An NFC MEI physical layer code factorization through the mei_phy NFC API. Both the microread and the pn544 drivers now use it. - LLCP aggregation support. This allows NFC p2p devices to send aggregated frames containing all sort of LLCP frames except SYMM and aggregation frames. - More LLCP socket options for getting the remote device link parameters. - Fixes for the LLCP socket option code added with the first pull request for 3.10. - Some support for LLCP corner cases like 0 length SDUs and general DISC (tagged with a 0,0 dsap ssap couple) handling. - RFKILL support for NFC. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRbIKSAAoJEIqAPN1PVmxK2pcQAIGch5i5hnxtw8ZWNmbJX6VR ZgKCXqU50v6nBibGEFBVb4kIrakV3AjIDdelFZedY1Zl2xIzZdAHfttTZm8NY4ra 9UHmk/lrqFhTWT88XycXGvYhVH38v/l2idRlLc2RsP/Z2gdy+3AqqLbz9z40NcTn FaWD9mzI34/3tn4hYRHxyn7IXJ+I6zer0+KmG9PqAkKwVK0AD/DaQLUcRSDHzn3g WlsP8XD6VQwaaeglWVnu2hepOZ+M4hgVRra4YHuj/JN///Bd9OSbUHA5T+om3HuA CAsDrHNq5pL+sMmNcF3hbwSYKJUD8grmCBpF2+Tyn689N/dO+vJL8uChTMSN24DV lF79uHVDz9BUHIvXZkH1uv0/ie4te2/XyAivbbE//Pz5Y0PRqXlV1it66tjGVCsL Y+opHD5lJJQ8fv4daEEDcuV/PFjVguH2bHIN5m75xWDy+oqzPvPV1FVrZwK50qO+ Yhesyl951xd8KbkrkUvfsUudizI5zPeT1NfJ+LmFtuC9KL2WCiep7MomdccA/UL/ 70o3cBB7D+bRv0ELXt6gG2jyGjy1m3jT1fyO54mCGdHwZlGrqOBWT7nhAnMJdPfw TOqUQnEdvweO0bPpnk+v3dh1w+4PkFBAvtEC8qFd7vDtpk/hgXaTuSUQzfOdgDsW S/q7sAi8N3YRNGbt4wGD =Y9pD -----END PGP SIGNATURE----- Merge tag 'nfc-next-3.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next Samuel Ortiz <sameo@linux.intel.com> says: "This is the 2nd NFC pull request for 3.10. With this one we have: - A major pn533 update. The pn533 framing support has been changed in order to easily support all pn533 derivatives. For example we now support the ACR122 USB dongle. - An NFC MEI physical layer code factorization through the mei_phy NFC API. Both the microread and the pn544 drivers now use it. - LLCP aggregation support. This allows NFC p2p devices to send aggregated frames containing all sort of LLCP frames except SYMM and aggregation frames. - More LLCP socket options for getting the remote device link parameters. - Fixes for the LLCP socket option code added with the first pull request for 3.10. - Some support for LLCP corner cases like 0 length SDUs and general DISC (tagged with a 0,0 dsap ssap couple) handling. - RFKILL support for NFC." Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
commit
197bbf0aed
@ -26,6 +26,16 @@ config NFC_WILINK
|
||||
Say Y here to compile support for Texas Instrument's NFC WiLink driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
||||
config NFC_MEI_PHY
|
||||
tristate "MEI bus NFC device support"
|
||||
depends on INTEL_MEI_BUS_NFC && NFC_HCI
|
||||
help
|
||||
This adds support to use an mei bus nfc device. Select this if you
|
||||
will use an HCI NFC driver for an NFC chip connected behind an
|
||||
Intel's Management Engine chip.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "drivers/nfc/pn544/Kconfig"
|
||||
source "drivers/nfc/microread/Kconfig"
|
||||
|
||||
|
@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544) += pn544/
|
||||
obj-$(CONFIG_NFC_MICROREAD) += microread/
|
||||
obj-$(CONFIG_NFC_PN533) += pn533.o
|
||||
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
||||
obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
|
||||
|
||||
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
|
||||
|
164
drivers/nfc/mei_phy.c
Normal file
164
drivers/nfc/mei_phy.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* MEI Library for mei bus nfc device access
|
||||
*
|
||||
* Copyright (C) 2013 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/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nfc.h>
|
||||
|
||||
#include "mei_phy.h"
|
||||
|
||||
struct mei_nfc_hdr {
|
||||
u8 cmd;
|
||||
u8 status;
|
||||
u16 req_id;
|
||||
u32 reserved;
|
||||
u16 data_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
|
||||
|
||||
#define MEI_DUMP_SKB_IN(info, skb) \
|
||||
do { \
|
||||
pr_debug("%s:\n", info); \
|
||||
print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, (skb)->data, (skb)->len, false); \
|
||||
} while (0)
|
||||
|
||||
#define MEI_DUMP_SKB_OUT(info, skb) \
|
||||
do { \
|
||||
pr_debug("%s:\n", info); \
|
||||
print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, (skb)->data, (skb)->len, false); \
|
||||
} while (0)
|
||||
|
||||
int nfc_mei_phy_enable(void *phy_id)
|
||||
{
|
||||
int r;
|
||||
struct nfc_mei_phy *phy = phy_id;
|
||||
|
||||
pr_info("%s\n", __func__);
|
||||
|
||||
if (phy->powered == 1)
|
||||
return 0;
|
||||
|
||||
r = mei_cl_enable_device(phy->device);
|
||||
if (r < 0) {
|
||||
pr_err("MEI_PHY: Could not enable device\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
phy->powered = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
|
||||
|
||||
void nfc_mei_phy_disable(void *phy_id)
|
||||
{
|
||||
struct nfc_mei_phy *phy = phy_id;
|
||||
|
||||
pr_info("%s\n", __func__);
|
||||
|
||||
mei_cl_disable_device(phy->device);
|
||||
|
||||
phy->powered = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
|
||||
|
||||
/*
|
||||
* Writing a frame must not return the number of written bytes.
|
||||
* It must return either zero for success, or <0 for error.
|
||||
* In addition, it must not alter the skb
|
||||
*/
|
||||
static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
|
||||
{
|
||||
struct nfc_mei_phy *phy = phy_id;
|
||||
int r;
|
||||
|
||||
MEI_DUMP_SKB_OUT("mei frame sent", skb);
|
||||
|
||||
r = mei_cl_send(phy->device, skb->data, skb->len);
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
|
||||
{
|
||||
struct nfc_mei_phy *phy = context;
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return;
|
||||
|
||||
if (events & BIT(MEI_CL_EVENT_RX)) {
|
||||
struct sk_buff *skb;
|
||||
int reply_size;
|
||||
|
||||
skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
|
||||
if (reply_size < MEI_NFC_HEADER_SIZE) {
|
||||
kfree(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_put(skb, reply_size);
|
||||
skb_pull(skb, MEI_NFC_HEADER_SIZE);
|
||||
|
||||
MEI_DUMP_SKB_IN("mei frame read", skb);
|
||||
|
||||
nfc_hci_recv_frame(phy->hdev, skb);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
|
||||
|
||||
struct nfc_phy_ops mei_phy_ops = {
|
||||
.write = nfc_mei_phy_write,
|
||||
.enable = nfc_mei_phy_enable,
|
||||
.disable = nfc_mei_phy_disable,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mei_phy_ops);
|
||||
|
||||
struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
|
||||
{
|
||||
struct nfc_mei_phy *phy;
|
||||
|
||||
phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return NULL;
|
||||
|
||||
phy->device = device;
|
||||
mei_cl_set_drvdata(device, phy);
|
||||
|
||||
return phy;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
|
||||
|
||||
void nfc_mei_phy_free(struct nfc_mei_phy *phy)
|
||||
{
|
||||
kfree(phy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("mei bus NFC device interface");
|
30
drivers/nfc/mei_phy.h
Normal file
30
drivers/nfc/mei_phy.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __LOCAL_MEI_PHY_H_
|
||||
#define __LOCAL_MEI_PHY_H_
|
||||
|
||||
#include <linux/mei_cl_bus.h>
|
||||
#include <net/nfc/hci.h>
|
||||
|
||||
#define MEI_NFC_HEADER_SIZE 10
|
||||
#define MEI_NFC_MAX_HCI_PAYLOAD 300
|
||||
|
||||
struct nfc_mei_phy {
|
||||
struct mei_cl_device *device;
|
||||
struct nfc_hci_dev *hdev;
|
||||
|
||||
int powered;
|
||||
|
||||
int hard_fault; /*
|
||||
* < 0 if hardware error occured
|
||||
* and prevents normal operation.
|
||||
*/
|
||||
};
|
||||
|
||||
extern struct nfc_phy_ops mei_phy_ops;
|
||||
|
||||
int nfc_mei_phy_enable(void *phy_id);
|
||||
void nfc_mei_phy_disable(void *phy_id);
|
||||
void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
|
||||
struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
|
||||
void nfc_mei_phy_free(struct nfc_mei_phy *phy);
|
||||
|
||||
#endif /* __LOCAL_MEI_PHY_H_ */
|
@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C
|
||||
|
||||
config NFC_MICROREAD_MEI
|
||||
tristate "NFC Microread MEI support"
|
||||
depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
|
||||
depends on NFC_MICROREAD && NFC_MEI_PHY
|
||||
---help---
|
||||
This module adds support for the mei interface of adapters using
|
||||
Inside microread chipsets. Select this if your microread chipset
|
||||
|
@ -19,151 +19,31 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mei_cl_bus.h>
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/hci.h>
|
||||
#include <net/nfc/llc.h>
|
||||
|
||||
#include "../mei_phy.h"
|
||||
#include "microread.h"
|
||||
|
||||
#define MICROREAD_DRIVER_NAME "microread"
|
||||
|
||||
struct mei_nfc_hdr {
|
||||
u8 cmd;
|
||||
u8 status;
|
||||
u16 req_id;
|
||||
u32 reserved;
|
||||
u16 data_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MEI_NFC_HEADER_SIZE 10
|
||||
#define MEI_NFC_MAX_HCI_PAYLOAD 300
|
||||
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
|
||||
|
||||
struct microread_mei_phy {
|
||||
struct mei_cl_device *device;
|
||||
struct nfc_hci_dev *hdev;
|
||||
|
||||
int powered;
|
||||
|
||||
int hard_fault; /*
|
||||
* < 0 if hardware error occured (e.g. i2c err)
|
||||
* and prevents normal operation.
|
||||
*/
|
||||
};
|
||||
|
||||
#define MEI_DUMP_SKB_IN(info, skb) \
|
||||
do { \
|
||||
pr_debug("%s:\n", info); \
|
||||
print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, (skb)->data, (skb)->len, 0); \
|
||||
} while (0)
|
||||
|
||||
#define MEI_DUMP_SKB_OUT(info, skb) \
|
||||
do { \
|
||||
pr_debug("%s:\n", info); \
|
||||
print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, (skb)->data, (skb)->len, 0); \
|
||||
} while (0)
|
||||
|
||||
static int microread_mei_enable(void *phy_id)
|
||||
{
|
||||
struct microread_mei_phy *phy = phy_id;
|
||||
|
||||
pr_info(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
phy->powered = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void microread_mei_disable(void *phy_id)
|
||||
{
|
||||
struct microread_mei_phy *phy = phy_id;
|
||||
|
||||
pr_info(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
phy->powered = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writing a frame must not return the number of written bytes.
|
||||
* It must return either zero for success, or <0 for error.
|
||||
* In addition, it must not alter the skb
|
||||
*/
|
||||
static int microread_mei_write(void *phy_id, struct sk_buff *skb)
|
||||
{
|
||||
struct microread_mei_phy *phy = phy_id;
|
||||
int r;
|
||||
|
||||
MEI_DUMP_SKB_OUT("mei frame sent", skb);
|
||||
|
||||
r = mei_cl_send(phy->device, skb->data, skb->len);
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void microread_event_cb(struct mei_cl_device *device, u32 events,
|
||||
void *context)
|
||||
{
|
||||
struct microread_mei_phy *phy = context;
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return;
|
||||
|
||||
if (events & BIT(MEI_CL_EVENT_RX)) {
|
||||
struct sk_buff *skb;
|
||||
int reply_size;
|
||||
|
||||
skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
|
||||
if (reply_size < MEI_NFC_HEADER_SIZE) {
|
||||
kfree(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_put(skb, reply_size);
|
||||
skb_pull(skb, MEI_NFC_HEADER_SIZE);
|
||||
|
||||
MEI_DUMP_SKB_IN("mei frame read", skb);
|
||||
|
||||
nfc_hci_recv_frame(phy->hdev, skb);
|
||||
}
|
||||
}
|
||||
|
||||
static struct nfc_phy_ops mei_phy_ops = {
|
||||
.write = microread_mei_write,
|
||||
.enable = microread_mei_enable,
|
||||
.disable = microread_mei_disable,
|
||||
};
|
||||
|
||||
static int microread_mei_probe(struct mei_cl_device *device,
|
||||
const struct mei_cl_device_id *id)
|
||||
{
|
||||
struct microread_mei_phy *phy;
|
||||
struct nfc_mei_phy *phy;
|
||||
int r;
|
||||
|
||||
pr_info("Probing NFC microread\n");
|
||||
|
||||
phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
|
||||
phy = nfc_mei_phy_alloc(device);
|
||||
if (!phy) {
|
||||
pr_err("Cannot allocate memory for microread mei phy.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy->device = device;
|
||||
mei_cl_set_drvdata(device, phy);
|
||||
|
||||
r = mei_cl_register_event_cb(device, microread_event_cb, phy);
|
||||
r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
|
||||
if (r) {
|
||||
pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
|
||||
goto err_out;
|
||||
@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device,
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
kfree(phy);
|
||||
nfc_mei_phy_free(phy);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int microread_mei_remove(struct mei_cl_device *device)
|
||||
{
|
||||
struct microread_mei_phy *phy = mei_cl_get_drvdata(device);
|
||||
struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
|
||||
|
||||
pr_info("Removing microread\n");
|
||||
|
||||
microread_remove(phy->hdev);
|
||||
|
||||
if (phy->powered)
|
||||
microread_mei_disable(phy);
|
||||
nfc_mei_phy_disable(phy);
|
||||
|
||||
kfree(phy);
|
||||
nfc_mei_phy_free(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,4 +20,15 @@ config NFC_PN544_I2C
|
||||
Select this if your platform is using the i2c bus.
|
||||
|
||||
If you choose to build a module, it'll be called pn544_i2c.
|
||||
Say N if unsure.
|
||||
Say N if unsure.
|
||||
|
||||
config NFC_PN544_MEI
|
||||
tristate "NFC PN544 MEI support"
|
||||
depends on NFC_PN544 && NFC_MEI_PHY
|
||||
---help---
|
||||
This module adds support for the mei interface of adapters using
|
||||
NXP pn544 chipsets. Select this if your pn544 chipset
|
||||
is handled by Intel's Management Engine Interface on your platform.
|
||||
|
||||
If you choose to build a module, it'll be called pn544_mei.
|
||||
Say N if unsure.
|
||||
|
@ -3,6 +3,8 @@
|
||||
#
|
||||
|
||||
pn544_i2c-objs = i2c.o
|
||||
pn544_mei-objs = mei.o
|
||||
|
||||
obj-$(CONFIG_NFC_PN544) += pn544.o
|
||||
obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
|
||||
obj-$(CONFIG_NFC_PN544_MEI) += pn544_mei.o
|
||||
|
121
drivers/nfc/pn544/mei.c
Normal file
121
drivers/nfc/pn544/mei.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* HCI based Driver for NXP pn544 NFC Chip
|
||||
*
|
||||
* Copyright (C) 2013 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/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/hci.h>
|
||||
#include <net/nfc/llc.h>
|
||||
|
||||
#include "../mei_phy.h"
|
||||
#include "pn544.h"
|
||||
|
||||
#define PN544_DRIVER_NAME "pn544"
|
||||
|
||||
static int pn544_mei_probe(struct mei_cl_device *device,
|
||||
const struct mei_cl_device_id *id)
|
||||
{
|
||||
struct nfc_mei_phy *phy;
|
||||
int r;
|
||||
|
||||
pr_info("Probing NFC pn544\n");
|
||||
|
||||
phy = nfc_mei_phy_alloc(device);
|
||||
if (!phy) {
|
||||
pr_err("Cannot allocate memory for pn544 mei phy.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
|
||||
if (r) {
|
||||
pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
|
||||
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
|
||||
&phy->hdev);
|
||||
if (r < 0)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
nfc_mei_phy_free(phy);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_mei_remove(struct mei_cl_device *device)
|
||||
{
|
||||
struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
|
||||
|
||||
pr_info("Removing pn544\n");
|
||||
|
||||
pn544_hci_remove(phy->hdev);
|
||||
|
||||
nfc_mei_phy_disable(phy);
|
||||
|
||||
nfc_mei_phy_free(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mei_cl_device_id pn544_mei_tbl[] = {
|
||||
{ PN544_DRIVER_NAME },
|
||||
|
||||
/* required last entry */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(mei, pn544_mei_tbl);
|
||||
|
||||
static struct mei_cl_driver pn544_driver = {
|
||||
.id_table = pn544_mei_tbl,
|
||||
.name = PN544_DRIVER_NAME,
|
||||
|
||||
.probe = pn544_mei_probe,
|
||||
.remove = pn544_mei_remove,
|
||||
};
|
||||
|
||||
static int pn544_mei_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
pr_debug(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
r = mei_cl_driver_register(&pn544_driver);
|
||||
if (r) {
|
||||
pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pn544_mei_exit(void)
|
||||
{
|
||||
mei_cl_driver_unregister(&pn544_driver);
|
||||
}
|
||||
|
||||
module_init(pn544_mei_init);
|
||||
module_exit(pn544_mei_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
@ -122,6 +122,8 @@ struct nfc_dev {
|
||||
|
||||
bool shutting_down;
|
||||
|
||||
struct rfkill *rfkill;
|
||||
|
||||
struct nfc_ops *ops;
|
||||
};
|
||||
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
||||
|
@ -233,7 +233,10 @@ struct sockaddr_nfc_llcp {
|
||||
#define NFC_LLCP_DIRECTION_TX 0x01
|
||||
|
||||
/* socket option names */
|
||||
#define NFC_LLCP_RW 0
|
||||
#define NFC_LLCP_MIUX 1
|
||||
#define NFC_LLCP_RW 0
|
||||
#define NFC_LLCP_MIUX 1
|
||||
#define NFC_LLCP_REMOTE_MIU 2
|
||||
#define NFC_LLCP_REMOTE_LTO 3
|
||||
#define NFC_LLCP_REMOTE_RW 4
|
||||
|
||||
#endif /*__LINUX_NFC_H */
|
||||
|
@ -37,6 +37,7 @@
|
||||
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
|
||||
* @RFKILL_TYPE_GPS: switch is on a GPS device.
|
||||
* @RFKILL_TYPE_FM: switch is on a FM radio device.
|
||||
* @RFKILL_TYPE_NFC: switch is on an NFC device.
|
||||
* @NUM_RFKILL_TYPES: number of defined rfkill types
|
||||
*/
|
||||
enum rfkill_type {
|
||||
@ -48,6 +49,7 @@ enum rfkill_type {
|
||||
RFKILL_TYPE_WWAN,
|
||||
RFKILL_TYPE_GPS,
|
||||
RFKILL_TYPE_FM,
|
||||
RFKILL_TYPE_NFC,
|
||||
NUM_RFKILL_TYPES,
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/nfc.h>
|
||||
|
||||
#include <net/genetlink.h>
|
||||
@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
|
||||
|
||||
device_lock(&dev->dev);
|
||||
|
||||
if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
|
||||
rc = -ERFKILL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!device_is_registered(&dev->dev)) {
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
@ -117,6 +123,24 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfc_rfkill_set_block(void *data, bool blocked)
|
||||
{
|
||||
struct nfc_dev *dev = data;
|
||||
|
||||
pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
|
||||
|
||||
if (!blocked)
|
||||
return 0;
|
||||
|
||||
nfc_dev_down(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops nfc_rfkill_ops = {
|
||||
.set_block = nfc_rfkill_set_block,
|
||||
};
|
||||
|
||||
/**
|
||||
* nfc_start_poll - start polling for nfc targets
|
||||
*
|
||||
@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!dev->dev_up) {
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (dev->polling) {
|
||||
rc = -EBUSY;
|
||||
goto error;
|
||||
@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
|
||||
pr_debug("The userspace won't be notified that the device %s was added\n",
|
||||
dev_name(&dev->dev));
|
||||
|
||||
dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
|
||||
RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
|
||||
if (dev->rfkill) {
|
||||
if (rfkill_register(dev->rfkill) < 0) {
|
||||
rfkill_destroy(dev->rfkill);
|
||||
dev->rfkill = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_register_device);
|
||||
@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
|
||||
|
||||
id = dev->idx;
|
||||
|
||||
if (dev->rfkill) {
|
||||
rfkill_unregister(dev->rfkill);
|
||||
rfkill_destroy(dev->rfkill);
|
||||
}
|
||||
|
||||
if (dev->ops->check_presence) {
|
||||
device_lock(&dev->dev);
|
||||
dev->shutting_down = true;
|
||||
|
@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
|
||||
}
|
||||
|
||||
/* If the socket parameters are not set, use the local ones */
|
||||
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
|
||||
miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
|
||||
local->miux : sock->miux;
|
||||
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
|
||||
|
||||
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
|
||||
@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
|
||||
return -ENODEV;
|
||||
|
||||
/* If the socket parameters are not set, use the local ones */
|
||||
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
|
||||
miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
|
||||
local->miux : sock->miux;
|
||||
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
|
||||
|
||||
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
|
||||
@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
|
||||
struct nfc_llcp_local *local;
|
||||
size_t frag_len = 0, remaining_len;
|
||||
u8 *msg_data, *msg_ptr;
|
||||
u16 remote_miu;
|
||||
|
||||
pr_debug("Send I frame len %zd\n", len);
|
||||
|
||||
@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
|
||||
remaining_len = len;
|
||||
msg_ptr = msg_data;
|
||||
|
||||
while (remaining_len > 0) {
|
||||
do {
|
||||
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
|
||||
local->remote_miu : sock->remote_miu;
|
||||
|
||||
frag_len = min_t(size_t, sock->remote_miu, remaining_len);
|
||||
frag_len = min_t(size_t, remote_miu, remaining_len);
|
||||
|
||||
pr_debug("Fragment %zd bytes remaining %zd",
|
||||
frag_len, remaining_len);
|
||||
@ -706,7 +711,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
|
||||
|
||||
skb_put(pdu, LLCP_SEQUENCE_SIZE);
|
||||
|
||||
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
|
||||
if (likely(frag_len > 0))
|
||||
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
|
||||
|
||||
skb_queue_tail(&sock->tx_queue, pdu);
|
||||
|
||||
@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
|
||||
|
||||
remaining_len -= frag_len;
|
||||
msg_ptr += frag_len;
|
||||
}
|
||||
} while (remaining_len > 0);
|
||||
|
||||
kfree(msg_data);
|
||||
|
||||
@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
|
||||
struct nfc_llcp_local *local;
|
||||
size_t frag_len = 0, remaining_len;
|
||||
u8 *msg_ptr, *msg_data;
|
||||
u16 remote_miu;
|
||||
int err;
|
||||
|
||||
pr_debug("Send UI frame len %zd\n", len);
|
||||
@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
|
||||
remaining_len = len;
|
||||
msg_ptr = msg_data;
|
||||
|
||||
while (remaining_len > 0) {
|
||||
do {
|
||||
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
|
||||
local->remote_miu : sock->remote_miu;
|
||||
|
||||
frag_len = min_t(size_t, sock->remote_miu, remaining_len);
|
||||
frag_len = min_t(size_t, remote_miu, remaining_len);
|
||||
|
||||
pr_debug("Fragment %zd bytes remaining %zd",
|
||||
frag_len, remaining_len);
|
||||
@ -768,14 +777,15 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
|
||||
|
||||
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
|
||||
|
||||
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
|
||||
if (likely(frag_len > 0))
|
||||
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
|
||||
|
||||
/* No need to check for the peer RW for UI frames */
|
||||
skb_queue_tail(&local->tx_queue, pdu);
|
||||
|
||||
remaining_len -= frag_len;
|
||||
msg_ptr += frag_len;
|
||||
}
|
||||
} while (remaining_len > 0);
|
||||
|
||||
kfree(msg_data);
|
||||
|
||||
|
@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
|
||||
|
||||
static struct list_head llcp_devices;
|
||||
|
||||
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
|
||||
|
||||
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
|
||||
{
|
||||
write_lock(&l->lock);
|
||||
@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
|
||||
write_unlock(&l->lock);
|
||||
}
|
||||
|
||||
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock)
|
||||
{
|
||||
sock->remote_rw = LLCP_DEFAULT_RW;
|
||||
sock->remote_miu = LLCP_MAX_MIU + 1;
|
||||
}
|
||||
|
||||
static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
|
||||
{
|
||||
struct nfc_llcp_local *local = sock->local;
|
||||
@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
|
||||
static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
|
||||
int err)
|
||||
{
|
||||
struct sock *sk;
|
||||
@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
|
||||
|
||||
bh_unlock_sock(accept_sk);
|
||||
}
|
||||
|
||||
if (listen == true) {
|
||||
bh_unlock_sock(sk);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a connection less socket bound, we keep it alive
|
||||
* if the device is still present.
|
||||
*/
|
||||
if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
|
||||
listen == true) {
|
||||
bh_unlock_sock(sk);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err)
|
||||
@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
|
||||
|
||||
write_unlock(&local->sockets.lock);
|
||||
|
||||
/*
|
||||
* If we want to keep the listening sockets alive,
|
||||
* we don't touch the RAW ones.
|
||||
*/
|
||||
if (listen == true)
|
||||
/* If we still have a device, we keep the RAW sockets alive */
|
||||
if (device == true)
|
||||
return;
|
||||
|
||||
write_lock(&local->raw_sockets.lock);
|
||||
@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
|
||||
return local;
|
||||
}
|
||||
|
||||
static void local_cleanup(struct nfc_llcp_local *local, bool listen)
|
||||
static void local_cleanup(struct nfc_llcp_local *local)
|
||||
{
|
||||
nfc_llcp_socket_release(local, listen, ENXIO);
|
||||
nfc_llcp_socket_release(local, false, ENXIO);
|
||||
del_timer_sync(&local->link_timer);
|
||||
skb_queue_purge(&local->tx_queue);
|
||||
cancel_work_sync(&local->tx_work);
|
||||
@ -194,7 +184,7 @@ static void local_release(struct kref *ref)
|
||||
local = container_of(ref, struct nfc_llcp_local, ref);
|
||||
|
||||
list_del(&local->list);
|
||||
local_cleanup(local, false);
|
||||
local_cleanup(local);
|
||||
kfree(local);
|
||||
}
|
||||
|
||||
@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
|
||||
dsap = nfc_llcp_dsap(skb);
|
||||
ssap = nfc_llcp_ssap(skb);
|
||||
|
||||
if ((dsap == 0) && (ssap == 0)) {
|
||||
pr_debug("Connection termination");
|
||||
nfc_dep_link_down(local->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
|
||||
if (llcp_sock == NULL) {
|
||||
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
|
||||
@ -1349,19 +1345,54 @@ exit:
|
||||
nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
|
||||
}
|
||||
|
||||
static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
|
||||
{
|
||||
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
|
||||
rx_work);
|
||||
u8 dsap, ssap, ptype;
|
||||
struct sk_buff *skb;
|
||||
u8 ptype;
|
||||
u16 pdu_len;
|
||||
struct sk_buff *new_skb;
|
||||
|
||||
skb = local->rx_pending;
|
||||
if (skb == NULL) {
|
||||
pr_debug("No pending SKB\n");
|
||||
if (skb->len <= LLCP_HEADER_SIZE) {
|
||||
pr_err("Malformed AGF PDU\n");
|
||||
return;
|
||||
}
|
||||
|
||||
skb_pull(skb, LLCP_HEADER_SIZE);
|
||||
|
||||
while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
|
||||
pdu_len = skb->data[0] << 8 | skb->data[1];
|
||||
|
||||
skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
|
||||
|
||||
if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
|
||||
pr_err("Malformed AGF PDU\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptype = nfc_llcp_ptype(skb);
|
||||
|
||||
if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
|
||||
goto next;
|
||||
|
||||
new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
|
||||
if (new_skb == NULL) {
|
||||
pr_err("Could not allocate PDU\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
|
||||
|
||||
nfc_llcp_rx_skb(local, new_skb);
|
||||
|
||||
kfree_skb(new_skb);
|
||||
next:
|
||||
skb_pull(skb, pdu_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
|
||||
{
|
||||
u8 dsap, ssap, ptype;
|
||||
|
||||
ptype = nfc_llcp_ptype(skb);
|
||||
dsap = nfc_llcp_dsap(skb);
|
||||
ssap = nfc_llcp_ssap(skb);
|
||||
@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
|
||||
16, 1, skb->data, skb->len, true);
|
||||
|
||||
__net_timestamp(skb);
|
||||
|
||||
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
|
||||
|
||||
switch (ptype) {
|
||||
case LLCP_PDU_SYMM:
|
||||
pr_debug("SYMM\n");
|
||||
@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
nfc_llcp_recv_hdlc(local, skb);
|
||||
break;
|
||||
|
||||
case LLCP_PDU_AGF:
|
||||
pr_debug("AGF frame\n");
|
||||
nfc_llcp_recv_agf(local, skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
{
|
||||
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
|
||||
rx_work);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = local->rx_pending;
|
||||
if (skb == NULL) {
|
||||
pr_debug("No pending SKB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
__net_timestamp(skb);
|
||||
|
||||
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
|
||||
|
||||
nfc_llcp_rx_skb(local, skb);
|
||||
|
||||
schedule_work(&local->tx_work);
|
||||
kfree_skb(local->rx_pending);
|
||||
@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
|
||||
if (local == NULL)
|
||||
return;
|
||||
|
||||
local->remote_miu = LLCP_DEFAULT_MIU;
|
||||
local->remote_lto = LLCP_DEFAULT_LTO;
|
||||
|
||||
/* Close and purge all existing sockets */
|
||||
nfc_llcp_socket_release(local, true, 0);
|
||||
}
|
||||
@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
local_cleanup(local, false);
|
||||
local_cleanup(local);
|
||||
|
||||
nfc_llcp_local_put(local);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ enum llcp_state {
|
||||
#define LLCP_MAX_LTO 0xff
|
||||
#define LLCP_MAX_RW 15
|
||||
#define LLCP_MAX_MIUX 0x7ff
|
||||
#define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128)
|
||||
|
||||
#define LLCP_WKS_NUM_SAP 16
|
||||
#define LLCP_SDP_NUM_SAP 16
|
||||
@ -124,7 +125,7 @@ struct nfc_llcp_sock {
|
||||
char *service_name;
|
||||
size_t service_name_len;
|
||||
u8 rw;
|
||||
u16 miux;
|
||||
__be16 miux;
|
||||
|
||||
|
||||
/* Remote link parameters */
|
||||
@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb {
|
||||
|
||||
#define LLCP_HEADER_SIZE 2
|
||||
#define LLCP_SEQUENCE_SIZE 1
|
||||
#define LLCP_AGF_PDU_HEADER_SIZE 2
|
||||
|
||||
/* LLCP versions: 1.1 is 1.0 plus SDP */
|
||||
#define LLCP_VERSION_10 0x10
|
||||
@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb {
|
||||
|
||||
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
|
||||
void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
|
||||
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
|
||||
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
|
||||
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
|
||||
int nfc_llcp_local_put(struct nfc_llcp_local *local);
|
||||
|
@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
llcp_sock->miux = (u16) opt;
|
||||
llcp_sock->miux = cpu_to_be16((u16) opt);
|
||||
|
||||
break;
|
||||
|
||||
@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
|
||||
static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct nfc_llcp_local *local;
|
||||
struct sock *sk = sock->sk;
|
||||
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
||||
int len, err = 0;
|
||||
u16 miux, remote_miu;
|
||||
u8 rw;
|
||||
|
||||
pr_debug("%p optname %d\n", sk, optname);
|
||||
|
||||
@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
local = llcp_sock->local;
|
||||
if (!local)
|
||||
return -ENODEV;
|
||||
|
||||
len = min_t(u32, len, sizeof(u32));
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
switch (optname) {
|
||||
case NFC_LLCP_RW:
|
||||
if (put_user(llcp_sock->rw, (u32 __user *) optval))
|
||||
rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
|
||||
if (put_user(rw, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case NFC_LLCP_MIUX:
|
||||
if (put_user(llcp_sock->miux, (u32 __user *) optval))
|
||||
miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
|
||||
be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
|
||||
|
||||
if (put_user(miux, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case NFC_LLCP_REMOTE_MIU:
|
||||
remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
|
||||
local->remote_miu : llcp_sock->remote_miu;
|
||||
|
||||
if (put_user(remote_miu, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case NFC_LLCP_REMOTE_LTO:
|
||||
if (put_user(local->remote_lto / 10, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case NFC_LLCP_REMOTE_RW:
|
||||
if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
@ -921,13 +953,12 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
|
||||
llcp_sock->ssap = 0;
|
||||
llcp_sock->dsap = LLCP_SAP_SDP;
|
||||
llcp_sock->rw = LLCP_MAX_RW + 1;
|
||||
llcp_sock->miux = LLCP_MAX_MIUX + 1;
|
||||
llcp_sock->remote_rw = LLCP_DEFAULT_RW;
|
||||
llcp_sock->remote_miu = LLCP_DEFAULT_MIU;
|
||||
llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
|
||||
llcp_sock->send_n = llcp_sock->send_ack_n = 0;
|
||||
llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
|
||||
llcp_sock->remote_ready = 1;
|
||||
llcp_sock->reserved_ssap = LLCP_SAP_MAX;
|
||||
nfc_llcp_socket_remote_param_init(llcp_sock);
|
||||
skb_queue_head_init(&llcp_sock->tx_queue);
|
||||
skb_queue_head_init(&llcp_sock->tx_pending_queue);
|
||||
INIT_LIST_HEAD(&llcp_sock->accept_queue);
|
||||
|
@ -587,7 +587,7 @@ static ssize_t rfkill_name_show(struct device *dev,
|
||||
|
||||
static const char *rfkill_get_type_str(enum rfkill_type type)
|
||||
{
|
||||
BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1);
|
||||
BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
|
||||
|
||||
switch (type) {
|
||||
case RFKILL_TYPE_WLAN:
|
||||
@ -604,6 +604,8 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
|
||||
return "gps";
|
||||
case RFKILL_TYPE_FM:
|
||||
return "fm";
|
||||
case RFKILL_TYPE_NFC:
|
||||
return "nfc";
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user