This is the first NFC patchset targeted at the 3.9 merge window.
It brings the following goodies: - LLCP socket timestamping (To be used e.g with the recently released nfctool application for a more efficient skb timestamping when sniffing). - A pretty big pn533 rework from Waldemar, preparing the driver to support more flavours of pn533 based devices. - HCI changes from Eric in preparation for the microread driver support. - Some LLCP memory leak fixes, cleanups and slight improvements. - pn544 and nfcwilink move to the devm_kzalloc API. - An initial Secure Element (SE) API. - An nfc.h license change from the original author, allowing non GPL application code to safely include it. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQ8+7TAAoJEIqAPN1PVmxKHQIP/3dfFPQsOxQRj6sIkFVE/Yzh AomeiBh5oGsZkxWzGEolWvHU+DEYTZFz/TKyhneHtWIENTj8+ueo1dh5i35DcKvL NiZJT3ASqyJV1ipwQG102y6J511pJsVoQkFSh0Xb/yTDNjwZnL9Jp2N3vsb3rJyN DzqNHOx+oCZvjeoGaUzRyjgndcWzeVw0f5IuyRJlCUdh9bj3Er1uP6ugCMiUkMBH FcY3Qwdc4WbgtpyYv+Y79/vny1kQ+JPf0Rk9VlylcFZ5RsLEc7K3G3rrTQZktlAT /fCVxURotu8XdFf6lj0qRHLnrnTICj1sDcApVOm2XtoXicOtw0q9GaUJVvgPChkc vJ2bAYrWMeQ1FZJQt5DaQdsfsglq64ROiAlI8/s9upKP3+Pt0HNnKqUXEZVYTnxZ wgFVj20nO2vl5tmI3Z65ZyA1cJ1uSsOcCH8sB7V+OJYQoSKWVyxJw5AOHHh3tHz7 +JfNrfTvIYG5woUivFmpdVslOHXMCe+lUfrXbvNCfF1PFsTUaQWa/dpxq6/pD991 eTn5uP+UoJqL5oiYQJzwbKMvQ+3qGPxQuaVhbicRQRiCYA3yflg43iN8aSe4ARzs 5dxY66WZgmAG1gamKxx7tJiPmkmgrrd/jAztLHdEZLmYnDUr+yQoazkaTOcWUCBt J7RoY3HcZsiDYwuB/D14 =YeWq -----END PGP SIGNATURE----- Merge tag 'nfc-next-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next Samuel Ortiz <sameo@linux.intel.com> says: "This is the first NFC patchset targeted at the 3.9 merge window. It brings the following goodies: - LLCP socket timestamping (To be used e.g with the recently released nfctool application for a more efficient skb timestamping when sniffing). - A pretty big pn533 rework from Waldemar, preparing the driver to support more flavours of pn533 based devices. - HCI changes from Eric in preparation for the microread driver support. - Some LLCP memory leak fixes, cleanups and slight improvements. - pn544 and nfcwilink move to the devm_kzalloc API. - An initial Secure Element (SE) API. - An nfc.h license change from the original author, allowing non GPL application code to safely include it." Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
commit
50c2f5e8f9
@ -17,10 +17,12 @@ HCI
|
||||
HCI registers as an nfc device with NFC Core. Requests coming from userspace are
|
||||
routed through netlink sockets to NFC Core and then to HCI. From this point,
|
||||
they are translated in a sequence of HCI commands sent to the HCI layer in the
|
||||
host controller (the chip). The sending context blocks while waiting for the
|
||||
response to arrive.
|
||||
host controller (the chip). Commands can be executed synchronously (the sending
|
||||
context blocks waiting for response) or asynchronously (the response is returned
|
||||
from HCI Rx context).
|
||||
HCI events can also be received from the host controller. They will be handled
|
||||
and a translation will be forwarded to NFC Core as needed.
|
||||
and a translation will be forwarded to NFC Core as needed. There are hooks to
|
||||
let the HCI driver handle proprietary events or override standard behavior.
|
||||
HCI uses 2 execution contexts:
|
||||
- one for executing commands : nfc_hci_msg_tx_work(). Only one command
|
||||
can be executing at any given moment.
|
||||
@ -33,6 +35,8 @@ The Session initialization is an HCI standard which must unfortunately
|
||||
support proprietary gates. This is the reason why the driver will pass a list
|
||||
of proprietary gates that must be part of the session. HCI will ensure all
|
||||
those gates have pipes connected when the hci device is set up.
|
||||
In case the chip supports pre-opened gates and pseudo-static pipes, the driver
|
||||
can pass that information to HCI core.
|
||||
|
||||
HCI Gates and Pipes
|
||||
-------------------
|
||||
@ -46,6 +50,13 @@ without knowing the pipe connected to it.
|
||||
Driver interface
|
||||
----------------
|
||||
|
||||
A driver is generally written in two parts : the physical link management and
|
||||
the HCI management. This makes it easier to maintain a driver for a chip that
|
||||
can be connected using various phy (i2c, spi, ...)
|
||||
|
||||
HCI Management
|
||||
--------------
|
||||
|
||||
A driver would normally register itself with HCI and provide the following
|
||||
entry points:
|
||||
|
||||
@ -53,58 +64,113 @@ struct nfc_hci_ops {
|
||||
int (*open)(struct nfc_hci_dev *hdev);
|
||||
void (*close)(struct nfc_hci_dev *hdev);
|
||||
int (*hci_ready) (struct nfc_hci_dev *hdev);
|
||||
int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
|
||||
int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
|
||||
struct nfc_target *target);
|
||||
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*start_poll) (struct nfc_hci_dev *hdev,
|
||||
u32 im_protocols, u32 tm_protocols);
|
||||
int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
|
||||
u8 comm_mode, u8 *gb, size_t gb_len);
|
||||
int (*dep_link_down)(struct nfc_hci_dev *hdev);
|
||||
int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
|
||||
struct nfc_target *target);
|
||||
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
|
||||
struct nfc_target *target);
|
||||
int (*data_exchange) (struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target,
|
||||
struct sk_buff *skb, struct sk_buff **res_skb);
|
||||
int (*im_transceive) (struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target, struct sk_buff *skb,
|
||||
data_exchange_cb_t cb, void *cb_context);
|
||||
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*check_presence)(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target);
|
||||
int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
struct sk_buff *skb);
|
||||
};
|
||||
|
||||
- open() and close() shall turn the hardware on and off.
|
||||
- hci_ready() is an optional entry point that is called right after the hci
|
||||
session has been set up. The driver can use it to do additional initialization
|
||||
that must be performed using HCI commands.
|
||||
- xmit() shall simply write a frame to the chip.
|
||||
- xmit() shall simply write a frame to the physical link.
|
||||
- start_poll() is an optional entrypoint that shall set the hardware in polling
|
||||
mode. This must be implemented only if the hardware uses proprietary gates or a
|
||||
mechanism slightly different from the HCI standard.
|
||||
- dep_link_up() is called after a p2p target has been detected, to finish
|
||||
the p2p connection setup with hardware parameters that need to be passed back
|
||||
to nfc core.
|
||||
- dep_link_down() is called to bring the p2p link down.
|
||||
- target_from_gate() is an optional entrypoint to return the nfc protocols
|
||||
corresponding to a proprietary gate.
|
||||
- complete_target_discovered() is an optional entry point to let the driver
|
||||
perform additional proprietary processing necessary to auto activate the
|
||||
discovered target.
|
||||
- data_exchange() must be implemented by the driver if proprietary HCI commands
|
||||
- im_transceive() must be implemented by the driver if proprietary HCI commands
|
||||
are required to send data to the tag. Some tag types will require custom
|
||||
commands, others can be written to using the standard HCI commands. The driver
|
||||
can check the tag type and either do proprietary processing, or return 1 to ask
|
||||
for standard processing.
|
||||
for standard processing. The data exchange command itself must be sent
|
||||
asynchronously.
|
||||
- tm_send() is called to send data in the case of a p2p connection
|
||||
- check_presence() is an optional entry point that will be called regularly
|
||||
by the core to check that an activated tag is still in the field. If this is
|
||||
not implemented, the core will not be able to push tag_lost events to the user
|
||||
space
|
||||
- event_received() is called to handle an event coming from the chip. Driver
|
||||
can handle the event or return 1 to let HCI attempt standard processing.
|
||||
|
||||
On the rx path, the driver is responsible to push incoming HCP frames to HCI
|
||||
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
|
||||
This must be done from a context that can sleep.
|
||||
|
||||
SHDLC
|
||||
-----
|
||||
PHY Management
|
||||
--------------
|
||||
|
||||
Most chips use shdlc to ensure integrity and delivery ordering of the HCP
|
||||
frames between the host controller (the chip) and hosts (entities connected
|
||||
to the chip, like the cpu). In order to simplify writing the driver, an shdlc
|
||||
layer is available for use by the driver.
|
||||
When used, the driver actually registers with shdlc, and shdlc will register
|
||||
with HCI. HCI sees shdlc as the driver and thus send its HCP frames
|
||||
through shdlc->xmit.
|
||||
SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state
|
||||
machine and handle both its rx and tx path.
|
||||
The physical link (i2c, ...) management is defined by the following struture:
|
||||
|
||||
struct nfc_phy_ops {
|
||||
int (*write)(void *dev_id, struct sk_buff *skb);
|
||||
int (*enable)(void *dev_id);
|
||||
void (*disable)(void *dev_id);
|
||||
};
|
||||
|
||||
enable(): turn the phy on (power on), make it ready to transfer data
|
||||
disable(): turn the phy off
|
||||
write(): Send a data frame to the chip. Note that to enable higher
|
||||
layers such as an llc to store the frame for re-emission, this function must
|
||||
not alter the skb. It must also not return a positive result (return 0 for
|
||||
success, negative for failure).
|
||||
|
||||
Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
|
||||
|
||||
LLC
|
||||
---
|
||||
|
||||
Communication between the CPU and the chip often requires some link layer
|
||||
protocol. Those are isolated as modules managed by the HCI layer. There are
|
||||
currently two modules : nop (raw transfert) and shdlc.
|
||||
A new llc must implement the following functions:
|
||||
|
||||
struct nfc_llc_ops {
|
||||
void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
|
||||
rcv_to_hci_t rcv_to_hci, int tx_headroom,
|
||||
int tx_tailroom, int *rx_headroom, int *rx_tailroom,
|
||||
llc_failure_t llc_failure);
|
||||
void (*deinit) (struct nfc_llc *llc);
|
||||
int (*start) (struct nfc_llc *llc);
|
||||
int (*stop) (struct nfc_llc *llc);
|
||||
void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
|
||||
int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
|
||||
};
|
||||
|
||||
- init() : allocate and init your private storage
|
||||
- deinit() : cleanup
|
||||
- start() : establish the logical connection
|
||||
- stop () : terminate the logical connection
|
||||
- rcv_from_drv() : handle data coming from the chip, going to HCI
|
||||
- xmit_from_hci() : handle data sent by HCI, going to the chip
|
||||
|
||||
The llc must be registered with nfc before it can be used. Do that by
|
||||
calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
|
||||
|
||||
Again, note that the llc does not handle the physical link. It is thus very
|
||||
easy to mix any physical link with any llc for a given chip driver.
|
||||
|
||||
Included Drivers
|
||||
----------------
|
||||
@ -117,10 +183,12 @@ Execution Contexts
|
||||
|
||||
The execution contexts are the following:
|
||||
- IRQ handler (IRQH):
|
||||
fast, cannot sleep. stores incoming frames into an shdlc rx queue
|
||||
fast, cannot sleep. sends incoming frames to HCI where they are passed to
|
||||
the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
|
||||
|
||||
- SHDLC State Machine worker (SMW)
|
||||
handles shdlc rx & tx queues. Dispatches HCI cmd responses.
|
||||
Only when llc_shdlc is used: handles shdlc rx & tx queues.
|
||||
Dispatches HCI cmd responses.
|
||||
|
||||
- HCI Tx Cmd worker (MSGTXWQ)
|
||||
Serializes execution of HCI commands. Completes execution in case of response
|
||||
@ -166,6 +234,15 @@ waiting command execution. Response processing involves invoking the completion
|
||||
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
|
||||
The completion callback will then wake the syscall context.
|
||||
|
||||
It is also possible to execute the command asynchronously using this API:
|
||||
|
||||
static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
|
||||
const u8 *param, size_t param_len,
|
||||
data_exchange_cb_t cb, void *cb_context)
|
||||
|
||||
The workflow is the same, except that the API call returns immediately, and
|
||||
the callback will be called with the result from the SMW context.
|
||||
|
||||
Workflow receiving an HCI event or command
|
||||
------------------------------------------
|
||||
|
||||
|
@ -1,32 +1,15 @@
|
||||
Kernel driver for the NXP Semiconductors PN544 Near Field
|
||||
Communication chip
|
||||
|
||||
Author: Jari Vanhala
|
||||
Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com)
|
||||
|
||||
General
|
||||
-------
|
||||
|
||||
The PN544 is an integrated transmission module for contactless
|
||||
communication. The driver goes under drives/nfc/ and is compiled as a
|
||||
module named "pn544". It registers a misc device and creates a device
|
||||
file named "/dev/pn544".
|
||||
module named "pn544".
|
||||
|
||||
Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
|
||||
|
||||
The Interface
|
||||
-------------
|
||||
|
||||
The driver offers a sysfs interface for a hardware test and an IOCTL
|
||||
interface for selecting between two operating modes. There are read,
|
||||
write and poll functions for transferring messages. The two operating
|
||||
modes are the normal (HCI) mode and the firmware update mode.
|
||||
|
||||
PN544 is controlled by sending messages from the userspace to the
|
||||
chip. The main function of the driver is just to pass those messages
|
||||
without caring about the message content.
|
||||
|
||||
|
||||
Protocols
|
||||
---------
|
||||
|
||||
@ -47,68 +30,3 @@ and third (LSB) bytes of the message. The maximum FW message length is
|
||||
|
||||
For the ETSI HCI specification see
|
||||
http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
|
||||
|
||||
The Hardware Test
|
||||
-----------------
|
||||
|
||||
The idea of the test is that it can performed by reading from the
|
||||
corresponding sysfs file. The test is implemented in the board file
|
||||
and it should test that PN544 can be put into the firmware update
|
||||
mode. If the test is not implemented the sysfs file does not get
|
||||
created.
|
||||
|
||||
Example:
|
||||
> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
|
||||
1
|
||||
|
||||
Normal Operation
|
||||
----------------
|
||||
|
||||
PN544 is powered up when the device file is opened, otherwise it's
|
||||
turned off. Only one instance can use the device at a time.
|
||||
|
||||
Userspace applications control PN544 with HCI messages. The hardware
|
||||
sends an interrupt when data is available for reading. Data is
|
||||
physically read when the read function is called by a userspace
|
||||
application. Poll() checks the read interrupt state. Configuration and
|
||||
self testing are also done from the userspace using read and write.
|
||||
|
||||
Example platform data:
|
||||
|
||||
static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
|
||||
{
|
||||
/* Get and setup the HW resources for the device */
|
||||
}
|
||||
|
||||
static void rx71_pn544_nfc_free_resources(void)
|
||||
{
|
||||
/* Release the HW resources */
|
||||
}
|
||||
|
||||
static void rx71_pn544_nfc_enable(int fw)
|
||||
{
|
||||
/* Turn the device on */
|
||||
}
|
||||
|
||||
static int rx71_pn544_nfc_test(void)
|
||||
{
|
||||
/*
|
||||
* Put the device into the FW update mode
|
||||
* and then back to the normal mode.
|
||||
* Check the behavior and return one on success,
|
||||
* zero on failure.
|
||||
*/
|
||||
}
|
||||
|
||||
static void rx71_pn544_nfc_disable(void)
|
||||
{
|
||||
/* turn the power off */
|
||||
}
|
||||
|
||||
static struct pn544_nfc_platform_data rx71_nfc_data = {
|
||||
.request_resources = rx71_pn544_nfc_request_resources,
|
||||
.free_resources = rx71_pn544_nfc_free_resources,
|
||||
.enable = rx71_pn544_nfc_enable,
|
||||
.test = rx71_pn544_nfc_test,
|
||||
.disable = rx71_pn544_nfc_disable,
|
||||
};
|
||||
|
@ -5,19 +5,6 @@
|
||||
menu "Near Field Communication (NFC) devices"
|
||||
depends on NFC
|
||||
|
||||
config PN544_HCI_NFC
|
||||
tristate "HCI PN544 NFC driver"
|
||||
depends on I2C && NFC_HCI && NFC_SHDLC
|
||||
select CRC_CCITT
|
||||
default n
|
||||
---help---
|
||||
NXP PN544 i2c driver.
|
||||
This is a driver based on the SHDLC and HCI NFC kernel layers and
|
||||
will thus not work with NXP libnfc library.
|
||||
|
||||
To compile this driver as a module, choose m here. The module will
|
||||
be called pn544_hci.
|
||||
|
||||
config NFC_PN533
|
||||
tristate "NXP PN533 USB driver"
|
||||
depends on USB
|
||||
@ -39,4 +26,6 @@ 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.
|
||||
|
||||
source "drivers/nfc/pn544/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for nfc devices
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PN544_HCI_NFC) += pn544/
|
||||
obj-$(CONFIG_NFC_PN544) += pn544/
|
||||
obj-$(CONFIG_NFC_PN533) += pn533.o
|
||||
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
||||
|
||||
|
@ -542,6 +542,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
|
||||
|
||||
drv->ndev = nci_allocate_device(&nfcwilink_ops,
|
||||
protocols,
|
||||
NFC_SE_NONE,
|
||||
NFCWILINK_HDR_LEN,
|
||||
0);
|
||||
if (!drv->ndev) {
|
||||
|
1635
drivers/nfc/pn533.c
1635
drivers/nfc/pn533.c
File diff suppressed because it is too large
Load Diff
23
drivers/nfc/pn544/Kconfig
Normal file
23
drivers/nfc/pn544/Kconfig
Normal file
@ -0,0 +1,23 @@
|
||||
config NFC_PN544
|
||||
tristate "NXP PN544 NFC driver"
|
||||
depends on NFC_HCI
|
||||
select CRC_CCITT
|
||||
default n
|
||||
---help---
|
||||
NXP PN544 core driver.
|
||||
This is a driver based on the HCI NFC kernel layers and
|
||||
will thus not work with NXP libnfc library.
|
||||
|
||||
To compile this driver as a module, choose m here. The module will
|
||||
be called pn544.
|
||||
Say N if unsure.
|
||||
|
||||
config NFC_PN544_I2C
|
||||
tristate "NFC PN544 i2c support"
|
||||
depends on NFC_PN544 && I2C && NFC_SHDLC
|
||||
---help---
|
||||
This module adds support for the NXP pn544 i2c interface.
|
||||
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.
|
@ -2,6 +2,7 @@
|
||||
# Makefile for PN544 HCI based NFC driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PN544_HCI_NFC) += pn544_i2c.o
|
||||
pn544_i2c-objs = i2c.o
|
||||
|
||||
pn544_i2c-y := pn544.o i2c.o
|
||||
obj-$(CONFIG_NFC_PN544) += pn544.o
|
||||
obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
|
||||
|
@ -376,12 +376,12 @@ static int __devinit pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL);
|
||||
phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
|
||||
GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(&client->dev,
|
||||
"Cannot allocate memory for pn544 i2c phy.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_phy_alloc;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy->i2c_dev = client;
|
||||
@ -390,20 +390,18 @@ static int __devinit pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
pdata = client->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&client->dev, "No platform data\n");
|
||||
r = -EINVAL;
|
||||
goto err_pdata;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->request_resources == NULL) {
|
||||
dev_err(&client->dev, "request_resources() missing\n");
|
||||
r = -EINVAL;
|
||||
goto err_pdata;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = pdata->request_resources(client);
|
||||
if (r) {
|
||||
dev_err(&client->dev, "Cannot get platform resources\n");
|
||||
goto err_pdata;
|
||||
return r;
|
||||
}
|
||||
|
||||
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
|
||||
@ -435,10 +433,6 @@ err_rti:
|
||||
if (pdata->free_resources != NULL)
|
||||
pdata->free_resources();
|
||||
|
||||
err_pdata:
|
||||
kfree(phy);
|
||||
|
||||
err_phy_alloc:
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -458,8 +452,6 @@ static __devexit int pn544_hci_i2c_remove(struct i2c_client *client)
|
||||
if (pdata->free_resources)
|
||||
pdata->free_resources();
|
||||
|
||||
kfree(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -472,29 +464,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
|
||||
.remove = __devexit_p(pn544_hci_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init pn544_hci_i2c_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
pr_debug(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
r = i2c_add_driver(&pn544_hci_i2c_driver);
|
||||
if (r) {
|
||||
pr_err(PN544_HCI_I2C_DRIVER_NAME
|
||||
": driver registration failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pn544_hci_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pn544_hci_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(pn544_hci_i2c_init);
|
||||
module_exit(pn544_hci_i2c_exit);
|
||||
module_i2c_driver(pn544_hci_i2c_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/hci.h>
|
||||
@ -675,11 +676,17 @@ static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
|
||||
|
||||
static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Set default false for multiple information chaining */
|
||||
*skb_push(skb, 1) = 0;
|
||||
|
||||
return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
|
||||
PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
|
||||
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;
|
||||
}
|
||||
|
||||
static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
|
||||
@ -714,35 +721,40 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
|
||||
u8 event, struct sk_buff *skb)
|
||||
/*
|
||||
* Returns:
|
||||
* <= 0: driver handled the event, skb consumed
|
||||
* 1: driver does not handle the event, please do standard processing
|
||||
*/
|
||||
static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *rgb_skb = NULL;
|
||||
int r = 0;
|
||||
int r;
|
||||
|
||||
pr_debug("hci event %d", event);
|
||||
switch (event) {
|
||||
case PN544_HCI_EVT_ACTIVATED:
|
||||
if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
|
||||
nfc_hci_target_discovered(hdev, gate);
|
||||
else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
|
||||
if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
|
||||
r = nfc_hci_target_discovered(hdev, gate);
|
||||
} else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
|
||||
r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
|
||||
&rgb_skb);
|
||||
|
||||
&rgb_skb);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
|
||||
NFC_COMM_PASSIVE, rgb_skb->data,
|
||||
rgb_skb->len);
|
||||
r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
|
||||
NFC_COMM_PASSIVE, rgb_skb->data,
|
||||
rgb_skb->len);
|
||||
|
||||
kfree_skb(rgb_skb);
|
||||
} else {
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
case PN544_HCI_EVT_DEACTIVATED:
|
||||
nfc_hci_send_event(hdev, gate,
|
||||
NFC_HCI_EVT_END_OPERATION, NULL, 0);
|
||||
r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
|
||||
NULL, 0);
|
||||
break;
|
||||
case PN544_HCI_EVT_RCV_DATA:
|
||||
if (skb->len < 2) {
|
||||
@ -757,15 +769,15 @@ static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
|
||||
}
|
||||
|
||||
skb_pull(skb, 2);
|
||||
nfc_tm_data_received(hdev->ndev, skb);
|
||||
|
||||
return;
|
||||
return nfc_tm_data_received(hdev->ndev, skb);
|
||||
default:
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
kfree_skb(skb);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct nfc_hci_ops pn544_hci_ops = {
|
||||
@ -789,7 +801,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
struct nfc_hci_dev **hdev)
|
||||
{
|
||||
struct pn544_hci_info *info;
|
||||
u32 protocols;
|
||||
u32 protocols, se;
|
||||
struct nfc_hci_init_data init_data;
|
||||
int r;
|
||||
|
||||
@ -822,8 +834,10 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
NFC_PROTO_ISO14443_B_MASK |
|
||||
NFC_PROTO_NFC_DEP_MASK;
|
||||
|
||||
info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
|
||||
protocols, llc_name,
|
||||
se = NFC_SE_UICC | NFC_SE_EMBEDDED;
|
||||
|
||||
info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
|
||||
protocols, se, llc_name,
|
||||
phy_headroom + PN544_CMDS_HEADROOM,
|
||||
phy_tailroom, phy_payload);
|
||||
if (!info->hdev) {
|
||||
@ -851,6 +865,7 @@ err_alloc_hdev:
|
||||
err_info_alloc:
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(pn544_hci_probe);
|
||||
|
||||
void pn544_hci_remove(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
@ -860,3 +875,7 @@ void pn544_hci_remove(struct nfc_hci_dev *hdev)
|
||||
nfc_hci_free_device(hdev);
|
||||
kfree(info);
|
||||
}
|
||||
EXPORT_SYMBOL(pn544_hci_remove);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
|
@ -57,8 +57,10 @@ struct nfc_hci_ops {
|
||||
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*check_presence)(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target);
|
||||
void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
struct sk_buff *skb);
|
||||
int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
struct sk_buff *skb);
|
||||
int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
|
||||
int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
|
||||
};
|
||||
|
||||
/* Pipes */
|
||||
@ -82,11 +84,23 @@ typedef int (*xmit) (struct sk_buff *skb, void *cb_data);
|
||||
|
||||
#define NFC_HCI_MAX_GATES 256
|
||||
|
||||
/*
|
||||
* These values can be specified by a driver to indicate it requires some
|
||||
* adaptation of the HCI standard.
|
||||
*
|
||||
* NFC_HCI_QUIRK_SHORT_CLEAR - send HCI_ADM_CLEAR_ALL_PIPE cmd with no params
|
||||
*/
|
||||
enum {
|
||||
NFC_HCI_QUIRK_SHORT_CLEAR = 0,
|
||||
};
|
||||
|
||||
struct nfc_hci_dev {
|
||||
struct nfc_dev *ndev;
|
||||
|
||||
u32 max_data_link_payload;
|
||||
|
||||
bool shutting_down;
|
||||
|
||||
struct mutex msg_tx_mutex;
|
||||
|
||||
struct list_head msg_tx_queue;
|
||||
@ -129,12 +143,16 @@ struct nfc_hci_dev {
|
||||
|
||||
u8 *gb;
|
||||
size_t gb_len;
|
||||
|
||||
unsigned long quirks;
|
||||
};
|
||||
|
||||
/* hci device allocation */
|
||||
struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
|
||||
struct nfc_hci_init_data *init_data,
|
||||
unsigned long quirks,
|
||||
u32 protocols,
|
||||
u32 supported_se,
|
||||
const char *llc_name,
|
||||
int tx_headroom,
|
||||
int tx_tailroom,
|
||||
|
@ -147,6 +147,7 @@ struct nci_dev {
|
||||
/* ----- NCI Devices ----- */
|
||||
struct nci_dev *nci_allocate_device(struct nci_ops *ops,
|
||||
__u32 supported_protocols,
|
||||
__u32 supported_se,
|
||||
int tx_headroom,
|
||||
int tx_tailroom);
|
||||
void nci_free_device(struct nci_dev *ndev);
|
||||
|
@ -68,6 +68,8 @@ struct nfc_ops {
|
||||
void *cb_context);
|
||||
int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
|
||||
int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
|
||||
int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
|
||||
int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
|
||||
};
|
||||
|
||||
#define NFC_TARGET_IDX_ANY -1
|
||||
@ -109,12 +111,17 @@ struct nfc_dev {
|
||||
struct nfc_genl_data genl_data;
|
||||
u32 supported_protocols;
|
||||
|
||||
u32 supported_se;
|
||||
u32 active_se;
|
||||
|
||||
int tx_headroom;
|
||||
int tx_tailroom;
|
||||
|
||||
struct timer_list check_pres_timer;
|
||||
struct work_struct check_pres_work;
|
||||
|
||||
bool shutting_down;
|
||||
|
||||
struct nfc_ops *ops;
|
||||
};
|
||||
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
||||
@ -123,6 +130,7 @@ extern struct class nfc_class;
|
||||
|
||||
struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
|
||||
u32 supported_protocols,
|
||||
u32 supported_se,
|
||||
int tx_headroom,
|
||||
int tx_tailroom);
|
||||
|
||||
|
@ -5,20 +5,17 @@
|
||||
* 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.
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* 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.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_NFC_H
|
||||
@ -67,6 +64,11 @@
|
||||
* subsequent CONNECT and CC messages.
|
||||
* If one of the passed parameters is wrong none is set and -EINVAL is
|
||||
* returned.
|
||||
* @NFC_CMD_ENABLE_SE: Enable the physical link to a specific secure element.
|
||||
* Once enabled a secure element will handle card emulation mode, i.e.
|
||||
* starting a poll from a device which has a secure element enabled means
|
||||
* we want to do SE based card emulation.
|
||||
* @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
|
||||
*/
|
||||
enum nfc_commands {
|
||||
NFC_CMD_UNSPEC,
|
||||
@ -86,6 +88,8 @@ enum nfc_commands {
|
||||
NFC_EVENT_TM_DEACTIVATED,
|
||||
NFC_CMD_LLC_GET_PARAMS,
|
||||
NFC_CMD_LLC_SET_PARAMS,
|
||||
NFC_CMD_ENABLE_SE,
|
||||
NFC_CMD_DISABLE_SE,
|
||||
/* private: internal use only */
|
||||
__NFC_CMD_AFTER_LAST
|
||||
};
|
||||
@ -114,6 +118,7 @@ enum nfc_commands {
|
||||
* @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter
|
||||
* @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter
|
||||
* @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter
|
||||
* @NFC_ATTR_SE: Available Secure Elements
|
||||
*/
|
||||
enum nfc_attrs {
|
||||
NFC_ATTR_UNSPEC,
|
||||
@ -134,6 +139,7 @@ enum nfc_attrs {
|
||||
NFC_ATTR_LLC_PARAM_LTO,
|
||||
NFC_ATTR_LLC_PARAM_RW,
|
||||
NFC_ATTR_LLC_PARAM_MIUX,
|
||||
NFC_ATTR_SE,
|
||||
/* private: internal use only */
|
||||
__NFC_ATTR_AFTER_LAST
|
||||
};
|
||||
@ -172,6 +178,11 @@ enum nfc_attrs {
|
||||
#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP)
|
||||
#define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B)
|
||||
|
||||
/* NFC Secure Elements */
|
||||
#define NFC_SE_NONE 0x0
|
||||
#define NFC_SE_UICC 0x1
|
||||
#define NFC_SE_EMBEDDED 0x2
|
||||
|
||||
struct sockaddr_nfc {
|
||||
sa_family_t sa_family;
|
||||
__u32 dev_idx;
|
||||
|
@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
|
||||
dev->active_target = target;
|
||||
dev->rf_mode = NFC_RF_INITIATOR;
|
||||
|
||||
if (dev->ops->check_presence)
|
||||
if (dev->ops->check_presence && !dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
}
|
||||
@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
|
||||
rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
|
||||
cb_context);
|
||||
|
||||
if (!rc && dev->ops->check_presence)
|
||||
if (!rc && dev->ops->check_presence && !dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
|
||||
@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
|
||||
|
||||
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
|
||||
|
||||
if (dev->ops->check_presence) {
|
||||
del_timer_sync(&dev->check_pres_timer);
|
||||
cancel_work_sync(&dev->check_pres_work);
|
||||
}
|
||||
|
||||
nfc_genl_data_exit(&dev->genl_data);
|
||||
kfree(dev->targets);
|
||||
kfree(dev);
|
||||
@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
|
||||
rc = dev->ops->check_presence(dev, dev->active_target);
|
||||
if (rc == -EOPNOTSUPP)
|
||||
goto exit;
|
||||
if (!rc) {
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
} else {
|
||||
if (rc) {
|
||||
u32 active_target_idx = dev->active_target->idx;
|
||||
device_unlock(&dev->dev);
|
||||
nfc_target_lost(dev, active_target_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -761,6 +757,7 @@ struct nfc_dev *nfc_get_device(unsigned int idx)
|
||||
*/
|
||||
struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
|
||||
u32 supported_protocols,
|
||||
u32 supported_se,
|
||||
int tx_headroom, int tx_tailroom)
|
||||
{
|
||||
struct nfc_dev *dev;
|
||||
@ -778,6 +775,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
|
||||
|
||||
dev->ops = ops;
|
||||
dev->supported_protocols = supported_protocols;
|
||||
dev->supported_se = supported_se;
|
||||
dev->active_se = NFC_SE_NONE;
|
||||
dev->tx_headroom = tx_headroom;
|
||||
dev->tx_tailroom = tx_tailroom;
|
||||
|
||||
@ -853,26 +852,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
|
||||
|
||||
id = dev->idx;
|
||||
|
||||
mutex_lock(&nfc_devlist_mutex);
|
||||
nfc_devlist_generation++;
|
||||
|
||||
/* lock to avoid unregistering a device while an operation
|
||||
is in progress */
|
||||
device_lock(&dev->dev);
|
||||
device_del(&dev->dev);
|
||||
device_unlock(&dev->dev);
|
||||
|
||||
mutex_unlock(&nfc_devlist_mutex);
|
||||
|
||||
nfc_llcp_unregister_device(dev);
|
||||
if (dev->ops->check_presence) {
|
||||
device_lock(&dev->dev);
|
||||
dev->shutting_down = true;
|
||||
device_unlock(&dev->dev);
|
||||
del_timer_sync(&dev->check_pres_timer);
|
||||
cancel_work_sync(&dev->check_pres_work);
|
||||
}
|
||||
|
||||
rc = nfc_genl_device_removed(dev);
|
||||
if (rc)
|
||||
pr_debug("The userspace won't be notified that the device %s was removed\n",
|
||||
dev_name(&dev->dev));
|
||||
pr_debug("The userspace won't be notified that the device %s "
|
||||
"was removed\n", dev_name(&dev->dev));
|
||||
|
||||
nfc_llcp_unregister_device(dev);
|
||||
|
||||
mutex_lock(&nfc_devlist_mutex);
|
||||
nfc_devlist_generation++;
|
||||
device_del(&dev->dev);
|
||||
mutex_unlock(&nfc_devlist_mutex);
|
||||
|
||||
ida_simple_remove(&nfc_index_ida, id);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_unregister_device);
|
||||
|
||||
|
@ -280,14 +280,19 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
|
||||
static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
u8 param[2];
|
||||
size_t param_len = 2;
|
||||
|
||||
/* TODO: Find out what the identity reference data is
|
||||
* and fill param with it. HCI spec 6.1.3.5 */
|
||||
|
||||
pr_debug("\n");
|
||||
|
||||
if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks))
|
||||
param_len = 0;
|
||||
|
||||
return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
|
||||
NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
|
||||
NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
|
||||
|
@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
if (hdev->shutting_down)
|
||||
goto exit;
|
||||
|
||||
if (hdev->cmd_pending_msg) {
|
||||
if (timer_pending(&hdev->cmd_timer) == 0) {
|
||||
@ -295,6 +297,12 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (hdev->ops->event_received) {
|
||||
r = hdev->ops->event_received(hdev, gate, event, skb);
|
||||
if (r <= 0)
|
||||
goto exit_noskb;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case NFC_HCI_EVT_TARGET_DISCOVERED:
|
||||
if (skb->len < 1) { /* no status data? */
|
||||
@ -320,17 +328,15 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
|
||||
r = nfc_hci_target_discovered(hdev, gate);
|
||||
break;
|
||||
default:
|
||||
if (hdev->ops->event_received) {
|
||||
hdev->ops->event_received(hdev, gate, event, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("Discarded unknown event %x to gate %x\n", event, gate);
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
kfree_skb(skb);
|
||||
|
||||
exit_noskb:
|
||||
if (r) {
|
||||
/* TODO: There was an error dispatching the event,
|
||||
* how to propagate up to nfc core?
|
||||
@ -669,8 +675,10 @@ static int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
|
||||
|
||||
if (hdev->ops->tm_send)
|
||||
return hdev->ops->tm_send(hdev, skb);
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int hci_check_presence(struct nfc_dev *nfc_dev,
|
||||
@ -787,7 +795,9 @@ static struct nfc_ops hci_nfc_ops = {
|
||||
|
||||
struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
|
||||
struct nfc_hci_init_data *init_data,
|
||||
unsigned long quirks,
|
||||
u32 protocols,
|
||||
u32 supported_se,
|
||||
const char *llc_name,
|
||||
int tx_headroom,
|
||||
int tx_tailroom,
|
||||
@ -813,7 +823,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols,
|
||||
hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, supported_se,
|
||||
tx_headroom + HCI_CMDS_HEADROOM,
|
||||
tx_tailroom);
|
||||
if (!hdev->ndev) {
|
||||
@ -830,6 +840,8 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
|
||||
|
||||
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
|
||||
|
||||
hdev->quirks = quirks;
|
||||
|
||||
return hdev;
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_hci_allocate_device);
|
||||
@ -868,6 +880,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
struct hci_msg *msg, *n;
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
|
||||
if (hdev->cmd_pending_msg) {
|
||||
if (hdev->cmd_pending_msg->cb)
|
||||
hdev->cmd_pending_msg->cb(
|
||||
hdev->cmd_pending_msg->cb_context,
|
||||
NULL, -ESHUTDOWN);
|
||||
kfree(hdev->cmd_pending_msg);
|
||||
hdev->cmd_pending_msg = NULL;
|
||||
}
|
||||
|
||||
hdev->shutting_down = true;
|
||||
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
|
||||
del_timer_sync(&hdev->cmd_timer);
|
||||
cancel_work_sync(&hdev->msg_tx_work);
|
||||
|
||||
cancel_work_sync(&hdev->msg_rx_work);
|
||||
|
||||
nfc_unregister_device(hdev->ndev);
|
||||
|
||||
skb_queue_purge(&hdev->rx_hcp_frags);
|
||||
skb_queue_purge(&hdev->msg_rx_queue);
|
||||
|
||||
@ -876,13 +910,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||
skb_queue_purge(&msg->msg_frags);
|
||||
kfree(msg);
|
||||
}
|
||||
|
||||
del_timer_sync(&hdev->cmd_timer);
|
||||
|
||||
nfc_unregister_device(hdev->ndev);
|
||||
|
||||
cancel_work_sync(&hdev->msg_tx_work);
|
||||
cancel_work_sync(&hdev->msg_rx_work);
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_hci_unregister_device);
|
||||
|
||||
|
@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
|
||||
}
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
|
||||
if (hdev->shutting_down) {
|
||||
err = -ESHUTDOWN;
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
goto out_skb_err;
|
||||
}
|
||||
|
||||
list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
|
||||
|
@ -304,6 +304,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
|
||||
|
||||
skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);
|
||||
|
||||
__net_timestamp(skb);
|
||||
|
||||
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX);
|
||||
|
||||
return nfc_data_exchange(dev, local->target_idx, skb,
|
||||
|
@ -54,7 +54,6 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
|
||||
|
||||
skb_queue_purge(&sock->tx_queue);
|
||||
skb_queue_purge(&sock->tx_pending_queue);
|
||||
skb_queue_purge(&sock->tx_backlog_queue);
|
||||
|
||||
if (local == NULL)
|
||||
return;
|
||||
@ -668,6 +667,8 @@ static void nfc_llcp_tx_work(struct work_struct *work)
|
||||
if (ptype == LLCP_PDU_I)
|
||||
copy_skb = skb_copy(skb, GFP_ATOMIC);
|
||||
|
||||
__net_timestamp(skb);
|
||||
|
||||
nfc_llcp_send_to_raw_sock(local, skb,
|
||||
NFC_LLCP_DIRECTION_TX);
|
||||
|
||||
@ -781,9 +782,15 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
|
||||
|
||||
/* There is no sequence with UI frames */
|
||||
skb_pull(skb, LLCP_HEADER_SIZE);
|
||||
if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
|
||||
pr_err("receive queue is full\n");
|
||||
skb_queue_head(&llcp_sock->tx_backlog_queue, skb);
|
||||
if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
|
||||
/*
|
||||
* UI frames will be freed from the socket layer, so we
|
||||
* need to keep them alive until someone receives them.
|
||||
*/
|
||||
skb_get(skb);
|
||||
} else {
|
||||
pr_err("Receive queue is full\n");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
nfc_llcp_sock_put(llcp_sock);
|
||||
@ -976,9 +983,15 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
|
||||
pr_err("Received out of sequence I PDU\n");
|
||||
|
||||
skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE);
|
||||
if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
|
||||
pr_err("receive queue is full\n");
|
||||
skb_queue_head(&llcp_sock->tx_backlog_queue, skb);
|
||||
if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
|
||||
/*
|
||||
* I frames will be freed from the socket layer, so we
|
||||
* need to keep them alive until someone receives them.
|
||||
*/
|
||||
skb_get(skb);
|
||||
} else {
|
||||
pr_err("Receive queue is full\n");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1245,6 +1258,8 @@ 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) {
|
||||
@ -1296,6 +1311,13 @@ static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
local->rx_pending = NULL;
|
||||
}
|
||||
|
||||
static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
|
||||
{
|
||||
local->rx_pending = skb;
|
||||
del_timer(&local->link_timer);
|
||||
schedule_work(&local->rx_work);
|
||||
}
|
||||
|
||||
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
|
||||
{
|
||||
struct nfc_llcp_local *local = (struct nfc_llcp_local *) data;
|
||||
@ -1306,9 +1328,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
|
||||
return;
|
||||
}
|
||||
|
||||
local->rx_pending = skb_get(skb);
|
||||
del_timer(&local->link_timer);
|
||||
schedule_work(&local->rx_work);
|
||||
__nfc_llcp_recv(local, skb);
|
||||
}
|
||||
|
||||
int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
|
||||
@ -1319,9 +1339,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
|
||||
if (local == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
local->rx_pending = skb_get(skb);
|
||||
del_timer(&local->link_timer);
|
||||
schedule_work(&local->rx_work);
|
||||
__nfc_llcp_recv(local, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ struct nfc_llcp_sock {
|
||||
|
||||
struct sk_buff_head tx_queue;
|
||||
struct sk_buff_head tx_pending_queue;
|
||||
struct sk_buff_head tx_backlog_queue;
|
||||
|
||||
struct list_head accept_queue;
|
||||
struct sock *parent;
|
||||
|
@ -672,25 +672,27 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
copied = min_t(unsigned int, rlen, len);
|
||||
|
||||
cskb = skb;
|
||||
if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
|
||||
if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
|
||||
if (!(flags & MSG_PEEK))
|
||||
skb_queue_head(&sk->sk_receive_queue, skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
sock_recv_timestamp(msg, sk, skb);
|
||||
|
||||
if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
|
||||
struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
|
||||
struct sockaddr_nfc_llcp sockaddr;
|
||||
struct sockaddr_nfc_llcp *sockaddr =
|
||||
(struct sockaddr_nfc_llcp *) msg->msg_name;
|
||||
|
||||
msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp);
|
||||
|
||||
pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
|
||||
|
||||
sockaddr.sa_family = AF_NFC;
|
||||
sockaddr.nfc_protocol = NFC_PROTO_NFC_DEP;
|
||||
sockaddr.dsap = ui_cb->dsap;
|
||||
sockaddr.ssap = ui_cb->ssap;
|
||||
|
||||
memcpy(msg->msg_name, &sockaddr, sizeof(sockaddr));
|
||||
msg->msg_namelen = sizeof(sockaddr);
|
||||
sockaddr->sa_family = AF_NFC;
|
||||
sockaddr->nfc_protocol = NFC_PROTO_NFC_DEP;
|
||||
sockaddr->dsap = ui_cb->dsap;
|
||||
sockaddr->ssap = ui_cb->ssap;
|
||||
}
|
||||
|
||||
/* Mark read part of skb as used */
|
||||
@ -806,7 +808,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
|
||||
llcp_sock->reserved_ssap = LLCP_SAP_MAX;
|
||||
skb_queue_head_init(&llcp_sock->tx_queue);
|
||||
skb_queue_head_init(&llcp_sock->tx_pending_queue);
|
||||
skb_queue_head_init(&llcp_sock->tx_backlog_queue);
|
||||
INIT_LIST_HEAD(&llcp_sock->accept_queue);
|
||||
|
||||
if (sock != NULL)
|
||||
@ -821,7 +822,6 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
|
||||
|
||||
skb_queue_purge(&sock->tx_queue);
|
||||
skb_queue_purge(&sock->tx_pending_queue);
|
||||
skb_queue_purge(&sock->tx_backlog_queue);
|
||||
|
||||
list_del_init(&sock->accept_queue);
|
||||
|
||||
|
@ -658,6 +658,7 @@ static struct nfc_ops nci_nfc_ops = {
|
||||
*/
|
||||
struct nci_dev *nci_allocate_device(struct nci_ops *ops,
|
||||
__u32 supported_protocols,
|
||||
__u32 supported_se,
|
||||
int tx_headroom, int tx_tailroom)
|
||||
{
|
||||
struct nci_dev *ndev;
|
||||
@ -680,6 +681,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
|
||||
|
||||
ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
|
||||
supported_protocols,
|
||||
supported_se,
|
||||
tx_headroom + NCI_DATA_HDR_SIZE,
|
||||
tx_tailroom);
|
||||
if (!ndev->nfc_dev)
|
||||
|
@ -366,6 +366,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
|
||||
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_u32(msg, NFC_ATTR_SE, dev->supported_se) ||
|
||||
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
|
||||
nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
|
||||
goto nla_put_failure;
|
||||
|
Loading…
Reference in New Issue
Block a user