xref: /OK3568_Linux_fs/kernel/drivers/nfc/nfcsim.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * NFC hardware simulation driver
4*4882a593Smuzhiyun  * Copyright (c) 2013, Intel Corporation.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/ctype.h>
11*4882a593Smuzhiyun #include <linux/debugfs.h>
12*4882a593Smuzhiyun #include <linux/nfc.h>
13*4882a593Smuzhiyun #include <net/nfc/nfc.h>
14*4882a593Smuzhiyun #include <net/nfc/digital.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \
17*4882a593Smuzhiyun 					    "%s: " fmt, __func__, ## args)
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \
20*4882a593Smuzhiyun 					    "%s: " fmt, __func__, ## args)
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define NFCSIM_VERSION "0.2"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define NFCSIM_MODE_NONE	0
25*4882a593Smuzhiyun #define NFCSIM_MODE_INITIATOR	1
26*4882a593Smuzhiyun #define NFCSIM_MODE_TARGET	2
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC   | \
29*4882a593Smuzhiyun 			     NFC_DIGITAL_DRV_CAPS_TG_CRC)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun struct nfcsim {
32*4882a593Smuzhiyun 	struct nfc_digital_dev *nfc_digital_dev;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	struct work_struct recv_work;
35*4882a593Smuzhiyun 	struct delayed_work send_work;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	struct nfcsim_link *link_in;
38*4882a593Smuzhiyun 	struct nfcsim_link *link_out;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	bool up;
41*4882a593Smuzhiyun 	u8 mode;
42*4882a593Smuzhiyun 	u8 rf_tech;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	u16 recv_timeout;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	nfc_digital_cmd_complete_t cb;
47*4882a593Smuzhiyun 	void *arg;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	u8 dropframe;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct nfcsim_link {
53*4882a593Smuzhiyun 	struct mutex lock;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	u8 rf_tech;
56*4882a593Smuzhiyun 	u8 mode;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	u8 shutdown;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	struct sk_buff *skb;
61*4882a593Smuzhiyun 	wait_queue_head_t recv_wait;
62*4882a593Smuzhiyun 	u8 cond;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
nfcsim_link_new(void)65*4882a593Smuzhiyun static struct nfcsim_link *nfcsim_link_new(void)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct nfcsim_link *link;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL);
70*4882a593Smuzhiyun 	if (!link)
71*4882a593Smuzhiyun 		return NULL;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	mutex_init(&link->lock);
74*4882a593Smuzhiyun 	init_waitqueue_head(&link->recv_wait);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return link;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
nfcsim_link_free(struct nfcsim_link * link)79*4882a593Smuzhiyun static void nfcsim_link_free(struct nfcsim_link *link)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	dev_kfree_skb(link->skb);
82*4882a593Smuzhiyun 	kfree(link);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
nfcsim_link_recv_wake(struct nfcsim_link * link)85*4882a593Smuzhiyun static void nfcsim_link_recv_wake(struct nfcsim_link *link)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	link->cond = 1;
88*4882a593Smuzhiyun 	wake_up_interruptible(&link->recv_wait);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
nfcsim_link_set_skb(struct nfcsim_link * link,struct sk_buff * skb,u8 rf_tech,u8 mode)91*4882a593Smuzhiyun static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb,
92*4882a593Smuzhiyun 				u8 rf_tech, u8 mode)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	mutex_lock(&link->lock);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	dev_kfree_skb(link->skb);
97*4882a593Smuzhiyun 	link->skb = skb;
98*4882a593Smuzhiyun 	link->rf_tech = rf_tech;
99*4882a593Smuzhiyun 	link->mode = mode;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	mutex_unlock(&link->lock);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
nfcsim_link_recv_cancel(struct nfcsim_link * link)104*4882a593Smuzhiyun static void nfcsim_link_recv_cancel(struct nfcsim_link *link)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	mutex_lock(&link->lock);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	link->mode = NFCSIM_MODE_NONE;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	mutex_unlock(&link->lock);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	nfcsim_link_recv_wake(link);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
nfcsim_link_shutdown(struct nfcsim_link * link)115*4882a593Smuzhiyun static void nfcsim_link_shutdown(struct nfcsim_link *link)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	mutex_lock(&link->lock);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	link->shutdown = 1;
120*4882a593Smuzhiyun 	link->mode = NFCSIM_MODE_NONE;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	mutex_unlock(&link->lock);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	nfcsim_link_recv_wake(link);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
nfcsim_link_recv_skb(struct nfcsim_link * link,int timeout,u8 rf_tech,u8 mode)127*4882a593Smuzhiyun static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link,
128*4882a593Smuzhiyun 					    int timeout, u8 rf_tech, u8 mode)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	int rc;
131*4882a593Smuzhiyun 	struct sk_buff *skb;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	rc = wait_event_interruptible_timeout(link->recv_wait,
134*4882a593Smuzhiyun 					      link->cond,
135*4882a593Smuzhiyun 					      msecs_to_jiffies(timeout));
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	mutex_lock(&link->lock);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	skb = link->skb;
140*4882a593Smuzhiyun 	link->skb = NULL;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (!rc) {
143*4882a593Smuzhiyun 		rc = -ETIMEDOUT;
144*4882a593Smuzhiyun 		goto done;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (!skb || link->rf_tech != rf_tech || link->mode == mode) {
148*4882a593Smuzhiyun 		rc = -EINVAL;
149*4882a593Smuzhiyun 		goto done;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (link->shutdown) {
153*4882a593Smuzhiyun 		rc = -ENODEV;
154*4882a593Smuzhiyun 		goto done;
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun done:
158*4882a593Smuzhiyun 	mutex_unlock(&link->lock);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (rc < 0) {
161*4882a593Smuzhiyun 		dev_kfree_skb(skb);
162*4882a593Smuzhiyun 		skb = ERR_PTR(rc);
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	link->cond = 0;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return skb;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
nfcsim_send_wq(struct work_struct * work)170*4882a593Smuzhiyun static void nfcsim_send_wq(struct work_struct *work)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	/*
175*4882a593Smuzhiyun 	 * To effectively send data, the device just wake up its link_out which
176*4882a593Smuzhiyun 	 * is the link_in of the peer device. The exchanged skb has already been
177*4882a593Smuzhiyun 	 * stored in the dev->link_out through nfcsim_link_set_skb().
178*4882a593Smuzhiyun 	 */
179*4882a593Smuzhiyun 	nfcsim_link_recv_wake(dev->link_out);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
nfcsim_recv_wq(struct work_struct * work)182*4882a593Smuzhiyun static void nfcsim_recv_wq(struct work_struct *work)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	struct nfcsim *dev = container_of(work, struct nfcsim, recv_work);
185*4882a593Smuzhiyun 	struct sk_buff *skb;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout,
188*4882a593Smuzhiyun 				   dev->rf_tech, dev->mode);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (!dev->up) {
191*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Device is down\n");
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 		if (!IS_ERR(skb))
194*4882a593Smuzhiyun 			dev_kfree_skb(skb);
195*4882a593Smuzhiyun 		return;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	dev->cb(dev->nfc_digital_dev, dev->arg, skb);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
nfcsim_send(struct nfc_digital_dev * ddev,struct sk_buff * skb,u16 timeout,nfc_digital_cmd_complete_t cb,void * arg)201*4882a593Smuzhiyun static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb,
202*4882a593Smuzhiyun 		       u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
205*4882a593Smuzhiyun 	u8 delay;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (!dev->up) {
208*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Device is down\n");
209*4882a593Smuzhiyun 		return -ENODEV;
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	dev->recv_timeout = timeout;
213*4882a593Smuzhiyun 	dev->cb = cb;
214*4882a593Smuzhiyun 	dev->arg = arg;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	schedule_work(&dev->recv_work);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (dev->dropframe) {
219*4882a593Smuzhiyun 		NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe);
220*4882a593Smuzhiyun 		dev_kfree_skb(skb);
221*4882a593Smuzhiyun 		dev->dropframe--;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		return 0;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (skb) {
227*4882a593Smuzhiyun 		nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech,
228*4882a593Smuzhiyun 				    dev->mode);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 		/* Add random delay (between 3 and 10 ms) before sending data */
231*4882a593Smuzhiyun 		get_random_bytes(&delay, 1);
232*4882a593Smuzhiyun 		delay = 3 + (delay & 0x07);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay));
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	return 0;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
nfcsim_abort_cmd(struct nfc_digital_dev * ddev)240*4882a593Smuzhiyun static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	nfcsim_link_recv_cancel(dev->link_in);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
nfcsim_switch_rf(struct nfc_digital_dev * ddev,bool on)247*4882a593Smuzhiyun static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	dev->up = on;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
nfcsim_in_configure_hw(struct nfc_digital_dev * ddev,int type,int param)256*4882a593Smuzhiyun static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev,
257*4882a593Smuzhiyun 					  int type, int param)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	switch (type) {
262*4882a593Smuzhiyun 	case NFC_DIGITAL_CONFIG_RF_TECH:
263*4882a593Smuzhiyun 		dev->up = true;
264*4882a593Smuzhiyun 		dev->mode = NFCSIM_MODE_INITIATOR;
265*4882a593Smuzhiyun 		dev->rf_tech = param;
266*4882a593Smuzhiyun 		break;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	case NFC_DIGITAL_CONFIG_FRAMING:
269*4882a593Smuzhiyun 		break;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	default:
272*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
273*4882a593Smuzhiyun 		return -EINVAL;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
nfcsim_in_send_cmd(struct nfc_digital_dev * ddev,struct sk_buff * skb,u16 timeout,nfc_digital_cmd_complete_t cb,void * arg)279*4882a593Smuzhiyun static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev,
280*4882a593Smuzhiyun 			       struct sk_buff *skb, u16 timeout,
281*4882a593Smuzhiyun 			       nfc_digital_cmd_complete_t cb, void *arg)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	return nfcsim_send(ddev, skb, timeout, cb, arg);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
nfcsim_tg_configure_hw(struct nfc_digital_dev * ddev,int type,int param)286*4882a593Smuzhiyun static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev,
287*4882a593Smuzhiyun 					  int type, int param)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	switch (type) {
292*4882a593Smuzhiyun 	case NFC_DIGITAL_CONFIG_RF_TECH:
293*4882a593Smuzhiyun 		dev->up = true;
294*4882a593Smuzhiyun 		dev->mode = NFCSIM_MODE_TARGET;
295*4882a593Smuzhiyun 		dev->rf_tech = param;
296*4882a593Smuzhiyun 		break;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	case NFC_DIGITAL_CONFIG_FRAMING:
299*4882a593Smuzhiyun 		break;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	default:
302*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
303*4882a593Smuzhiyun 		return -EINVAL;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
nfcsim_tg_send_cmd(struct nfc_digital_dev * ddev,struct sk_buff * skb,u16 timeout,nfc_digital_cmd_complete_t cb,void * arg)309*4882a593Smuzhiyun static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev,
310*4882a593Smuzhiyun 			       struct sk_buff *skb, u16 timeout,
311*4882a593Smuzhiyun 			       nfc_digital_cmd_complete_t cb, void *arg)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	return nfcsim_send(ddev, skb, timeout, cb, arg);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
nfcsim_tg_listen(struct nfc_digital_dev * ddev,u16 timeout,nfc_digital_cmd_complete_t cb,void * arg)316*4882a593Smuzhiyun static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
317*4882a593Smuzhiyun 			    nfc_digital_cmd_complete_t cb, void *arg)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	return nfcsim_send(ddev, NULL, timeout, cb, arg);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun static struct nfc_digital_ops nfcsim_digital_ops = {
323*4882a593Smuzhiyun 	.in_configure_hw = nfcsim_in_configure_hw,
324*4882a593Smuzhiyun 	.in_send_cmd = nfcsim_in_send_cmd,
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	.tg_listen = nfcsim_tg_listen,
327*4882a593Smuzhiyun 	.tg_configure_hw = nfcsim_tg_configure_hw,
328*4882a593Smuzhiyun 	.tg_send_cmd = nfcsim_tg_send_cmd,
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	.abort_cmd = nfcsim_abort_cmd,
331*4882a593Smuzhiyun 	.switch_rf = nfcsim_switch_rf,
332*4882a593Smuzhiyun };
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun static struct dentry *nfcsim_debugfs_root;
335*4882a593Smuzhiyun 
nfcsim_debugfs_init(void)336*4882a593Smuzhiyun static void nfcsim_debugfs_init(void)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (!nfcsim_debugfs_root)
341*4882a593Smuzhiyun 		pr_err("Could not create debugfs entry\n");
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
nfcsim_debugfs_remove(void)345*4882a593Smuzhiyun static void nfcsim_debugfs_remove(void)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	debugfs_remove_recursive(nfcsim_debugfs_root);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
nfcsim_debugfs_init_dev(struct nfcsim * dev)350*4882a593Smuzhiyun static void nfcsim_debugfs_init_dev(struct nfcsim *dev)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct dentry *dev_dir;
353*4882a593Smuzhiyun 	char devname[5]; /* nfcX\0 */
354*4882a593Smuzhiyun 	u32 idx;
355*4882a593Smuzhiyun 	int n;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (!nfcsim_debugfs_root) {
358*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n");
359*4882a593Smuzhiyun 		return;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	idx = dev->nfc_digital_dev->nfc_dev->idx;
363*4882a593Smuzhiyun 	n = snprintf(devname, sizeof(devname), "nfc%d", idx);
364*4882a593Smuzhiyun 	if (n >= sizeof(devname)) {
365*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx);
366*4882a593Smuzhiyun 		return;
367*4882a593Smuzhiyun 	}
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root);
370*4882a593Smuzhiyun 	if (!dev_dir) {
371*4882a593Smuzhiyun 		NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n",
372*4882a593Smuzhiyun 			   idx);
373*4882a593Smuzhiyun 		return;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
nfcsim_device_new(struct nfcsim_link * link_in,struct nfcsim_link * link_out)379*4882a593Smuzhiyun static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in,
380*4882a593Smuzhiyun 					struct nfcsim_link *link_out)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	struct nfcsim *dev;
383*4882a593Smuzhiyun 	int rc;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL);
386*4882a593Smuzhiyun 	if (!dev)
387*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq);
390*4882a593Smuzhiyun 	INIT_WORK(&dev->recv_work, nfcsim_recv_wq);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	dev->nfc_digital_dev =
393*4882a593Smuzhiyun 			nfc_digital_allocate_device(&nfcsim_digital_ops,
394*4882a593Smuzhiyun 						    NFC_PROTO_NFC_DEP_MASK,
395*4882a593Smuzhiyun 						    NFCSIM_CAPABILITIES,
396*4882a593Smuzhiyun 						    0, 0);
397*4882a593Smuzhiyun 	if (!dev->nfc_digital_dev) {
398*4882a593Smuzhiyun 		kfree(dev);
399*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	nfc_digital_set_drvdata(dev->nfc_digital_dev, dev);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	dev->link_in = link_in;
405*4882a593Smuzhiyun 	dev->link_out = link_out;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	rc = nfc_digital_register_device(dev->nfc_digital_dev);
408*4882a593Smuzhiyun 	if (rc) {
409*4882a593Smuzhiyun 		pr_err("Could not register digital device (%d)\n", rc);
410*4882a593Smuzhiyun 		nfc_digital_free_device(dev->nfc_digital_dev);
411*4882a593Smuzhiyun 		kfree(dev);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 		return ERR_PTR(rc);
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	nfcsim_debugfs_init_dev(dev);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return dev;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
nfcsim_device_free(struct nfcsim * dev)421*4882a593Smuzhiyun static void nfcsim_device_free(struct nfcsim *dev)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun 	nfc_digital_unregister_device(dev->nfc_digital_dev);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	dev->up = false;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	nfcsim_link_shutdown(dev->link_in);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	cancel_delayed_work_sync(&dev->send_work);
430*4882a593Smuzhiyun 	cancel_work_sync(&dev->recv_work);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	nfc_digital_free_device(dev->nfc_digital_dev);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	kfree(dev);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun static struct nfcsim *dev0;
438*4882a593Smuzhiyun static struct nfcsim *dev1;
439*4882a593Smuzhiyun 
nfcsim_init(void)440*4882a593Smuzhiyun static int __init nfcsim_init(void)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	struct nfcsim_link *link0, *link1;
443*4882a593Smuzhiyun 	int rc;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	link0 = nfcsim_link_new();
446*4882a593Smuzhiyun 	link1 = nfcsim_link_new();
447*4882a593Smuzhiyun 	if (!link0 || !link1) {
448*4882a593Smuzhiyun 		rc = -ENOMEM;
449*4882a593Smuzhiyun 		goto exit_err;
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	nfcsim_debugfs_init();
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	dev0 = nfcsim_device_new(link0, link1);
455*4882a593Smuzhiyun 	if (IS_ERR(dev0)) {
456*4882a593Smuzhiyun 		rc = PTR_ERR(dev0);
457*4882a593Smuzhiyun 		goto exit_err;
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	dev1 = nfcsim_device_new(link1, link0);
461*4882a593Smuzhiyun 	if (IS_ERR(dev1)) {
462*4882a593Smuzhiyun 		nfcsim_device_free(dev0);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 		rc = PTR_ERR(dev1);
465*4882a593Smuzhiyun 		goto exit_err;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	pr_info("nfcsim " NFCSIM_VERSION " initialized\n");
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	return 0;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun exit_err:
473*4882a593Smuzhiyun 	pr_err("Failed to initialize nfcsim driver (%d)\n", rc);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	if (link0)
476*4882a593Smuzhiyun 		nfcsim_link_free(link0);
477*4882a593Smuzhiyun 	if (link1)
478*4882a593Smuzhiyun 		nfcsim_link_free(link1);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return rc;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
nfcsim_exit(void)483*4882a593Smuzhiyun static void __exit nfcsim_exit(void)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct nfcsim_link *link0, *link1;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	link0 = dev0->link_in;
488*4882a593Smuzhiyun 	link1 = dev0->link_out;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	nfcsim_device_free(dev0);
491*4882a593Smuzhiyun 	nfcsim_device_free(dev1);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	nfcsim_link_free(link0);
494*4882a593Smuzhiyun 	nfcsim_link_free(link1);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	nfcsim_debugfs_remove();
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun module_init(nfcsim_init);
500*4882a593Smuzhiyun module_exit(nfcsim_exit);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
503*4882a593Smuzhiyun MODULE_VERSION(NFCSIM_VERSION);
504*4882a593Smuzhiyun MODULE_LICENSE("GPL");
505