Commit 412fda53 authored by Eric Lapuyade's avatar Eric Lapuyade Committed by Samuel Ortiz

NFC: Changed HCI and PN544 HCI driver to use the new HCI LLC Core

The previous shdlc HCI driver and its header are removed from the tree.
PN544 now registers directly with HCI and passes the name of the llc it
requires (shdlc).
HCI instantiation now allocates the required llc instance. The llc is
started when the HCI device is brought up.
Signed-off-by: default avatarEric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 4a61cd66
......@@ -19,7 +19,7 @@ config PN544_NFC
config PN544_HCI_NFC
tristate "HCI PN544 NFC driver"
depends on I2C && NFC_SHDLC
depends on I2C && NFC_HCI && NFC_SHDLC
select CRC_CCITT
default n
---help---
......
......@@ -29,7 +29,7 @@
#include <linux/nfc.h>
#include <net/nfc/hci.h>
#include <net/nfc/shdlc.h>
#include <net/nfc/llc.h>
#include <linux/nfc/pn544.h>
......@@ -133,7 +133,7 @@ static struct nfc_hci_gate pn544_gates[] = {
struct pn544_hci_info {
struct i2c_client *i2c_dev;
struct nfc_shdlc *shdlc;
struct nfc_hci_dev *hdev;
enum pn544_state state;
......@@ -362,21 +362,21 @@ static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id)
if (r == -EREMOTEIO) {
info->hard_fault = r;
nfc_shdlc_recv_frame(info->shdlc, NULL);
nfc_hci_recv_frame(info->hdev, NULL);
return IRQ_HANDLED;
} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
return IRQ_HANDLED;
}
nfc_shdlc_recv_frame(info->shdlc, skb);
nfc_hci_recv_frame(info->hdev, skb);
return IRQ_HANDLED;
}
static int pn544_hci_open(struct nfc_shdlc *shdlc)
static int pn544_hci_open(struct nfc_hci_dev *hdev)
{
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
int r = 0;
mutex_lock(&info->info_lock);
......@@ -396,9 +396,9 @@ static int pn544_hci_open(struct nfc_shdlc *shdlc)
return r;
}
static void pn544_hci_close(struct nfc_shdlc *shdlc)
static void pn544_hci_close(struct nfc_hci_dev *hdev)
{
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
mutex_lock(&info->info_lock);
......@@ -413,9 +413,8 @@ static void pn544_hci_close(struct nfc_shdlc *shdlc)
mutex_unlock(&info->info_lock);
}
static int pn544_hci_ready(struct nfc_shdlc *shdlc)
static int pn544_hci_ready(struct nfc_hci_dev *hdev)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
struct sk_buff *skb;
static struct hw_config {
u8 adr[2];
......@@ -601,9 +600,9 @@ static void pn544_hci_remove_len_crc(struct sk_buff *skb)
skb_trim(skb, PN544_FRAME_TAILROOM);
}
static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
{
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
struct i2c_client *client = info->i2c_dev;
int r;
......@@ -617,10 +616,9 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
return r;
}
static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
u8 phases = 0;
int r;
u8 duration[2];
......@@ -671,7 +669,7 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
return r;
}
static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate,
static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target)
{
switch (gate) {
......@@ -689,11 +687,10 @@ static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate,
return 0;
}
static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
u8 gate,
struct nfc_target *target)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
struct sk_buff *uid_skb;
int r = 0;
......@@ -765,13 +762,12 @@ static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
* <= 0: driver handled the data exchange
* 1: driver doesn't especially handle, please do standard processing
*/
static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev,
struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context)
{
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
target->hci_reader_gate);
......@@ -824,17 +820,15 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
}
}
static int pn544_hci_check_presence(struct nfc_shdlc *shdlc,
static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
struct nfc_target *target)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
PN544_RF_READER_CMD_PRESENCE_CHECK,
NULL, 0, NULL);
}
static struct nfc_shdlc_ops pn544_shdlc_ops = {
static struct nfc_hci_ops pn544_hci_ops = {
.open = pn544_hci_open,
.close = pn544_hci_close,
.hci_ready = pn544_hci_ready,
......@@ -926,23 +920,30 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,
NFC_PROTO_ISO14443_B_MASK |
NFC_PROTO_NFC_DEP_MASK;
info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops,
&init_data, protocols,
PN544_FRAME_HEADROOM + PN544_CMDS_HEADROOM,
PN544_FRAME_TAILROOM,
PN544_HCI_LLC_MAX_PAYLOAD,
dev_name(&client->dev));
if (!info->shdlc) {
dev_err(&client->dev, "Cannot allocate nfc shdlc.\n");
info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
protocols, LLC_SHDLC_NAME,
PN544_FRAME_HEADROOM +
PN544_CMDS_HEADROOM,
PN544_FRAME_TAILROOM,
PN544_HCI_LLC_MAX_PAYLOAD);
if (!info->hdev) {
dev_err(&client->dev, "Cannot allocate nfc hdev.\n");
r = -ENOMEM;
goto err_allocshdlc;
goto err_alloc_hdev;
}
nfc_shdlc_set_clientdata(info->shdlc, info);
nfc_hci_set_clientdata(info->hdev, info);
r = nfc_hci_register_device(info->hdev);
if (r)
goto err_regdev;
return 0;
err_allocshdlc:
err_regdev:
nfc_hci_free_device(info->hdev);
err_alloc_hdev:
free_irq(client->irq, info);
err_rti:
......@@ -963,7 +964,7 @@ static __devexit int pn544_hci_remove(struct i2c_client *client)
dev_dbg(&client->dev, "%s\n", __func__);
nfc_shdlc_free(info->shdlc);
nfc_hci_free_device(info->hdev);
if (info->state != PN544_ST_COLD) {
if (pdata->disable)
......
......@@ -87,6 +87,8 @@ struct nfc_hci_dev {
struct nfc_hci_ops *ops;
struct nfc_llc *llc;
struct nfc_hci_init_data init_data;
void *clientdata;
......@@ -113,6 +115,7 @@ struct nfc_hci_dev {
struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
struct nfc_hci_init_data *init_data,
u32 protocols,
const char *llc_name,
int tx_headroom,
int tx_tailroom,
int max_link_payload);
......
/*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*
* 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 __NFC_SHDLC_H
#define __NFC_SHDLC_H
struct nfc_shdlc;
struct nfc_shdlc_ops {
int (*open) (struct nfc_shdlc *shdlc);
void (*close) (struct nfc_shdlc *shdlc);
int (*hci_ready) (struct nfc_shdlc *shdlc);
int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb);
int (*start_poll) (struct nfc_shdlc *shdlc,
u32 im_protocols, u32 tm_protocols);
int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,
struct nfc_target *target);
int (*data_exchange) (struct nfc_shdlc *shdlc,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context);
int (*check_presence)(struct nfc_shdlc *shdlc,
struct nfc_target *target);
};
enum shdlc_state {
SHDLC_DISCONNECTED = 0,
SHDLC_CONNECTING = 1,
SHDLC_NEGOCIATING = 2,
SHDLC_CONNECTED = 3
};
struct nfc_shdlc {
struct mutex state_mutex;
enum shdlc_state state;
int hard_fault;
struct nfc_hci_dev *hdev;
wait_queue_head_t *connect_wq;
int connect_tries;
int connect_result;
struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */
u8 w; /* window size */
bool srej_support;
struct timer_list t1_timer; /* send ack timeout */
bool t1_active;
struct timer_list t2_timer; /* guard/retransmit timeout */
bool t2_active;
int ns; /* next seq num for send */
int nr; /* next expected seq num for receive */
int dnr; /* oldest sent unacked seq num */
struct sk_buff_head rcv_q;
struct sk_buff_head send_q;
bool rnr; /* other side is not ready to receive */
struct sk_buff_head ack_pending_q;
struct work_struct sm_work;
struct nfc_shdlc_ops *ops;
int client_headroom;
int client_tailroom;
void *clientdata;
};
void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb);
struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops,
struct nfc_hci_init_data *init_data,
u32 protocols,
int tx_headroom, int tx_tailroom,
int max_link_payload, const char *devname);
void nfc_shdlc_free(struct nfc_shdlc *shdlc);
void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata);
void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc);
struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc);
#endif /* __NFC_SHDLC_H */
......@@ -5,4 +5,4 @@
obj-$(CONFIG_NFC_HCI) += hci.o
hci-y := core.o hcp.o command.o llc.o llc_nop.o
hci-$(CONFIG_NFC_SHDLC) += shdlc.o llc_shdlc.o
hci-$(CONFIG_NFC_SHDLC) += llc_shdlc.o
......@@ -78,7 +78,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
pr_debug("msg_tx_queue has a cmd to send\n");
while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) {
r = hdev->ops->xmit(hdev, skb);
r = nfc_llc_xmit_from_hci(hdev->llc, skb);
if (r < 0) {
kfree_skb(skb);
skb_queue_purge(&msg->msg_frags);
......@@ -469,29 +469,38 @@ static int hci_dev_up(struct nfc_dev *nfc_dev)
return r;
}
r = nfc_llc_start(hdev->llc);
if (r < 0)
goto exit_close;
r = hci_dev_session_init(hdev);
if (r < 0)
goto exit;
goto exit_llc;
r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_END_OPERATION, NULL, 0);
if (r < 0)
goto exit;
goto exit_llc;
if (hdev->ops->hci_ready) {
r = hdev->ops->hci_ready(hdev);
if (r < 0)
goto exit;
goto exit_llc;
}
r = hci_dev_version(hdev);
if (r < 0)
goto exit;
goto exit_llc;
return 0;
exit_llc:
nfc_llc_stop(hdev->llc);
exit_close:
if (hdev->ops->close)
hdev->ops->close(hdev);
exit:
if (r < 0)
if (hdev->ops->close)
hdev->ops->close(hdev);
return r;
}
......@@ -499,6 +508,8 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
nfc_llc_stop(hdev->llc);
if (hdev->ops->close)
hdev->ops->close(hdev);
......@@ -620,6 +631,93 @@ static int hci_check_presence(struct nfc_dev *nfc_dev,
return 0;
}
static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err)
{
mutex_lock(&hdev->msg_tx_mutex);
if (hdev->cmd_pending_msg == NULL) {
nfc_driver_failure(hdev->ndev, err);
goto exit;
}
__nfc_hci_cmd_completion(hdev, err, NULL);
exit:
mutex_unlock(&hdev->msg_tx_mutex);
}
static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err)
{
nfc_hci_failure(hdev, err);
}
static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb)
{
struct hcp_packet *packet;
u8 type;
u8 instruction;
struct sk_buff *hcp_skb;
u8 pipe;
struct sk_buff *frag_skb;
int msg_len;
packet = (struct hcp_packet *)skb->data;
if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) {
skb_queue_tail(&hdev->rx_hcp_frags, skb);
return;
}
/* it's the last fragment. Does it need re-aggregation? */
if (skb_queue_len(&hdev->rx_hcp_frags)) {
pipe = packet->header & NFC_HCI_FRAGMENT;
skb_queue_tail(&hdev->rx_hcp_frags, skb);
msg_len = 0;
skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
msg_len += (frag_skb->len -
NFC_HCI_HCP_PACKET_HEADER_LEN);
}
hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN +
msg_len, GFP_KERNEL);
if (hcp_skb == NULL) {
nfc_hci_failure(hdev, -ENOMEM);
return;
}
*skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe;
skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN;
memcpy(skb_put(hcp_skb, msg_len),
frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN,
msg_len);
}
skb_queue_purge(&hdev->rx_hcp_frags);
} else {
packet->header &= NFC_HCI_FRAGMENT;
hcp_skb = skb;
}
/* if this is a response, dispatch immediately to
* unblock waiting cmd context. Otherwise, enqueue to dispatch
* in separate context where handler can also execute command.
*/
packet = (struct hcp_packet *)hcp_skb->data;
type = HCP_MSG_GET_TYPE(packet->message.header);
if (type == NFC_HCI_HCP_RESPONSE) {
pipe = packet->header;
instruction = HCP_MSG_GET_CMD(packet->message.header);
skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN +
NFC_HCI_HCP_MESSAGE_HEADER_LEN);
nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb);
} else {
skb_queue_tail(&hdev->msg_rx_queue, hcp_skb);
queue_work(system_nrt_wq, &hdev->msg_rx_work);
}
}
static struct nfc_ops hci_nfc_ops = {
.dev_up = hci_dev_up,
.dev_down = hci_dev_down,
......@@ -634,6 +732,7 @@ 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,
u32 protocols,
const char *llc_name,
int tx_headroom,
int tx_tailroom,
int max_link_payload)
......@@ -650,10 +749,19 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
if (hdev == NULL)
return NULL;
hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit,
nfc_hci_recv_from_llc, tx_headroom,
tx_tailroom, nfc_hci_llc_failure);
if (hdev->llc == NULL) {
kfree(hdev);
return NULL;
}
hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols,
tx_headroom + HCI_CMDS_HEADROOM,
tx_tailroom);
if (!hdev->ndev) {
nfc_llc_free(hdev->llc);
kfree(hdev);
return NULL;
}
......@@ -673,6 +781,7 @@ EXPORT_SYMBOL(nfc_hci_allocate_device);
void nfc_hci_free_device(struct nfc_hci_dev *hdev)
{
nfc_free_device(hdev->ndev);
nfc_llc_free(hdev->llc);
kfree(hdev);
}
EXPORT_SYMBOL(nfc_hci_free_device);
......@@ -733,92 +842,15 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev)
}
EXPORT_SYMBOL(nfc_hci_get_clientdata);
static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err)
{
mutex_lock(&hdev->msg_tx_mutex);
if (hdev->cmd_pending_msg == NULL) {
nfc_driver_failure(hdev->ndev, err);
goto exit;
}
__nfc_hci_cmd_completion(hdev, err, NULL);
exit:
mutex_unlock(&hdev->msg_tx_mutex);
}
void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err)
{
nfc_hci_failure(hdev, err);
}
EXPORT_SYMBOL(nfc_hci_driver_failure);
void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
{
struct hcp_packet *packet;
u8 type;
u8 instruction;
struct sk_buff *hcp_skb;
u8 pipe;
struct sk_buff *frag_skb;
int msg_len;
packet = (struct hcp_packet *)skb->data;
if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) {
skb_queue_tail(&hdev->rx_hcp_frags, skb);
return;
}
/* it's the last fragment. Does it need re-aggregation? */
if (skb_queue_len(&hdev->rx_hcp_frags)) {
pipe = packet->header & NFC_HCI_FRAGMENT;
skb_queue_tail(&hdev->rx_hcp_frags, skb);
msg_len = 0;
skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
msg_len += (frag_skb->len -
NFC_HCI_HCP_PACKET_HEADER_LEN);
}
hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN +
msg_len, GFP_KERNEL);
if (hcp_skb == NULL) {
nfc_hci_failure(hdev, -ENOMEM);
return;
}
*skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe;
skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN;
memcpy(skb_put(hcp_skb, msg_len),
frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN,
msg_len);
}
skb_queue_purge(&hdev->rx_hcp_frags);
} else {
packet->header &= NFC_HCI_FRAGMENT;
hcp_skb = skb;
}
/* if this is a response, dispatch immediately to
* unblock waiting cmd context. Otherwise, enqueue to dispatch
* in separate context where handler can also execute command.
*/
packet = (struct hcp_packet *)hcp_skb->data;
type = HCP_MSG_GET_TYPE(packet->message.header);
if (type == NFC_HCI_HCP_RESPONSE) {
pipe = packet->header;
instruction = HCP_MSG_GET_CMD(packet->message.header);
skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN +
NFC_HCI_HCP_MESSAGE_HEADER_LEN);
nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb);
} else {
skb_queue_tail(&hdev->msg_rx_queue, hcp_skb);
queue_work(system_nrt_wq, &hdev->msg_rx_work);
}
nfc_llc_rcv_from_drv(hdev->llc, skb);
}
EXPORT_SYMBOL(nfc_hci_recv_frame);
......@@ -832,7 +864,7 @@ static void __exit nfc_hci_exit(void)
nfc_llc_exit();
}
module_init(nfc_hci_init);
subsys_initcall(nfc_hci_init);
module_exit(nfc_hci_exit);
MODULE_LICENSE("GPL");
......@@ -535,7 +535,7 @@ static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc)
pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns,
shdlc->nr);
/* SHDLC_DUMP_SKB("shdlc frame written", skb); */
SHDLC_DUMP_SKB("shdlc frame written", skb);
r = shdlc->xmit_to_drv(shdlc->hdev, skb);
if (r < 0) {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment