xref: /linux/drivers/nfc/nfcmrvl/usb.c (revision 3ce095c16263630dde46d6051854073edaacf3d7)
1 /**
2  * Marvell NFC-over-USB driver: USB interface related functions
3  *
4  * Copyright (C) 2014, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8  * (the "License").  You may use, redistribute and/or modify this File in
9  * accordance with the terms and conditions of the License, a copy of which
10  * is available on the worldwide web at
11  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12  *
13  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
14  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
15  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
16  * this warranty disclaimer.
17  **/
18 
19 #include <linux/module.h>
20 #include <linux/usb.h>
21 #include <linux/nfc.h>
22 #include <net/nfc/nci.h>
23 #include <net/nfc/nci_core.h>
24 #include "nfcmrvl.h"
25 
26 #define VERSION "1.0"
27 
28 static struct usb_device_id nfcmrvl_table[] = {
29 	{ USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
30 	{ }	/* Terminating entry */
31 };
32 
33 MODULE_DEVICE_TABLE(usb, nfcmrvl_table);
34 
35 #define NFCMRVL_USB_BULK_RUNNING	1
36 #define NFCMRVL_USB_SUSPENDING		2
37 
38 struct nfcmrvl_usb_drv_data {
39 	struct usb_device *udev;
40 	struct usb_interface *intf;
41 	unsigned long flags;
42 	struct work_struct waker;
43 	struct usb_anchor tx_anchor;
44 	struct usb_anchor bulk_anchor;
45 	struct usb_anchor deferred;
46 	int tx_in_flight;
47 	/* protects tx_in_flight */
48 	spinlock_t txlock;
49 	struct usb_endpoint_descriptor *bulk_tx_ep;
50 	struct usb_endpoint_descriptor *bulk_rx_ep;
51 	int suspend_count;
52 	struct nfcmrvl_private *priv;
53 };
54 
55 static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
56 {
57 	unsigned long flags;
58 	int rv;
59 
60 	spin_lock_irqsave(&drv_data->txlock, flags);
61 	rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
62 	if (!rv)
63 		drv_data->tx_in_flight++;
64 	spin_unlock_irqrestore(&drv_data->txlock, flags);
65 
66 	return rv;
67 }
68 
69 static void nfcmrvl_bulk_complete(struct urb *urb)
70 {
71 	struct nfcmrvl_usb_drv_data *drv_data = urb->context;
72 	int err;
73 
74 	dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
75 		urb, urb->status, urb->actual_length);
76 
77 	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
78 		return;
79 
80 	if (!urb->status) {
81 		if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
82 					   urb->actual_length) < 0)
83 			nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n");
84 	}
85 
86 	if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
87 		return;
88 
89 	usb_anchor_urb(urb, &drv_data->bulk_anchor);
90 	usb_mark_last_busy(drv_data->udev);
91 
92 	err = usb_submit_urb(urb, GFP_ATOMIC);
93 	if (err) {
94 		/* -EPERM: urb is being killed;
95 		 * -ENODEV: device got disconnected
96 		 */
97 		if (err != -EPERM && err != -ENODEV)
98 			nfc_err(&drv_data->udev->dev,
99 				"urb %p failed to resubmit (%d)\n", urb, -err);
100 		usb_unanchor_urb(urb);
101 	}
102 }
103 
104 static int
105 nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
106 {
107 	struct urb *urb;
108 	unsigned char *buf;
109 	unsigned int pipe;
110 	int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE;
111 
112 	if (!drv_data->bulk_rx_ep)
113 		return -ENODEV;
114 
115 	urb = usb_alloc_urb(0, mem_flags);
116 	if (!urb)
117 		return -ENOMEM;
118 
119 	buf = kmalloc(size, mem_flags);
120 	if (!buf) {
121 		usb_free_urb(urb);
122 		return -ENOMEM;
123 	}
124 
125 	pipe = usb_rcvbulkpipe(drv_data->udev,
126 			       drv_data->bulk_rx_ep->bEndpointAddress);
127 
128 	usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
129 			  nfcmrvl_bulk_complete, drv_data);
130 
131 	urb->transfer_flags |= URB_FREE_BUFFER;
132 
133 	usb_mark_last_busy(drv_data->udev);
134 	usb_anchor_urb(urb, &drv_data->bulk_anchor);
135 
136 	err = usb_submit_urb(urb, mem_flags);
137 	if (err) {
138 		if (err != -EPERM && err != -ENODEV)
139 			nfc_err(&drv_data->udev->dev,
140 				"urb %p submission failed (%d)\n", urb, -err);
141 		usb_unanchor_urb(urb);
142 	}
143 
144 	usb_free_urb(urb);
145 
146 	return err;
147 }
148 
149 static void nfcmrvl_tx_complete(struct urb *urb)
150 {
151 	struct sk_buff *skb = urb->context;
152 	struct nci_dev *ndev = (struct nci_dev *)skb->dev;
153 	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
154 	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
155 
156 	nfc_info(priv->dev, "urb %p status %d count %d\n",
157 		 urb, urb->status, urb->actual_length);
158 
159 	spin_lock(&drv_data->txlock);
160 	drv_data->tx_in_flight--;
161 	spin_unlock(&drv_data->txlock);
162 
163 	kfree(urb->setup_packet);
164 	kfree_skb(skb);
165 }
166 
167 static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
168 {
169 	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
170 	int err;
171 
172 	err = usb_autopm_get_interface(drv_data->intf);
173 	if (err)
174 		return err;
175 
176 	drv_data->intf->needs_remote_wakeup = 1;
177 
178 	err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
179 	if (err)
180 		goto failed;
181 
182 	set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
183 	nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
184 
185 	usb_autopm_put_interface(drv_data->intf);
186 	return 0;
187 
188 failed:
189 	usb_autopm_put_interface(drv_data->intf);
190 	return err;
191 }
192 
193 static void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data)
194 {
195 	usb_kill_anchored_urbs(&drv_data->bulk_anchor);
196 }
197 
198 static int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv)
199 {
200 	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
201 	int err;
202 
203 	cancel_work_sync(&drv_data->waker);
204 
205 	clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
206 
207 	nfcmrvl_usb_stop_traffic(drv_data);
208 	usb_kill_anchored_urbs(&drv_data->tx_anchor);
209 	err = usb_autopm_get_interface(drv_data->intf);
210 	if (err)
211 		goto failed;
212 
213 	drv_data->intf->needs_remote_wakeup = 0;
214 	usb_autopm_put_interface(drv_data->intf);
215 
216 failed:
217 	usb_scuttle_anchored_urbs(&drv_data->deferred);
218 	return 0;
219 }
220 
221 static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
222 				struct sk_buff *skb)
223 {
224 	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
225 	struct urb *urb;
226 	unsigned int pipe;
227 	int err;
228 
229 	if (!drv_data->bulk_tx_ep)
230 		return -ENODEV;
231 
232 	urb = usb_alloc_urb(0, GFP_ATOMIC);
233 	if (!urb)
234 		return -ENOMEM;
235 
236 	pipe = usb_sndbulkpipe(drv_data->udev,
237 				drv_data->bulk_tx_ep->bEndpointAddress);
238 
239 	usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len,
240 			  nfcmrvl_tx_complete, skb);
241 
242 	err = nfcmrvl_inc_tx(drv_data);
243 	if (err) {
244 		usb_anchor_urb(urb, &drv_data->deferred);
245 		schedule_work(&drv_data->waker);
246 		err = 0;
247 		goto done;
248 	}
249 
250 	usb_anchor_urb(urb, &drv_data->tx_anchor);
251 
252 	err = usb_submit_urb(urb, GFP_ATOMIC);
253 	if (err) {
254 		if (err != -EPERM && err != -ENODEV)
255 			nfc_err(&drv_data->udev->dev,
256 				"urb %p submission failed (%d)\n", urb, -err);
257 		kfree(urb->setup_packet);
258 		usb_unanchor_urb(urb);
259 	} else {
260 		usb_mark_last_busy(drv_data->udev);
261 	}
262 
263 done:
264 	usb_free_urb(urb);
265 	return err;
266 }
267 
268 static struct nfcmrvl_if_ops usb_ops = {
269 	.nci_open = nfcmrvl_usb_nci_open,
270 	.nci_close = nfcmrvl_usb_nci_close,
271 	.nci_send = nfcmrvl_usb_nci_send,
272 };
273 
274 static void nfcmrvl_waker(struct work_struct *work)
275 {
276 	struct nfcmrvl_usb_drv_data *drv_data =
277 			container_of(work, struct nfcmrvl_usb_drv_data, waker);
278 	int err;
279 
280 	err = usb_autopm_get_interface(drv_data->intf);
281 	if (err)
282 		return;
283 
284 	usb_autopm_put_interface(drv_data->intf);
285 }
286 
287 static int nfcmrvl_probe(struct usb_interface *intf,
288 			 const struct usb_device_id *id)
289 {
290 	struct usb_endpoint_descriptor *ep_desc;
291 	struct nfcmrvl_usb_drv_data *drv_data;
292 	struct nfcmrvl_private *priv;
293 	int i;
294 	struct usb_device *udev = interface_to_usbdev(intf);
295 
296 	nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
297 
298 	drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
299 	if (!drv_data)
300 		return -ENOMEM;
301 
302 	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
303 		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
304 
305 		if (!drv_data->bulk_tx_ep &&
306 		    usb_endpoint_is_bulk_out(ep_desc)) {
307 			drv_data->bulk_tx_ep = ep_desc;
308 			continue;
309 		}
310 
311 		if (!drv_data->bulk_rx_ep &&
312 		    usb_endpoint_is_bulk_in(ep_desc)) {
313 			drv_data->bulk_rx_ep = ep_desc;
314 			continue;
315 		}
316 	}
317 
318 	if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep)
319 		return -ENODEV;
320 
321 	drv_data->udev = udev;
322 	drv_data->intf = intf;
323 
324 	INIT_WORK(&drv_data->waker, nfcmrvl_waker);
325 	spin_lock_init(&drv_data->txlock);
326 
327 	init_usb_anchor(&drv_data->tx_anchor);
328 	init_usb_anchor(&drv_data->bulk_anchor);
329 	init_usb_anchor(&drv_data->deferred);
330 
331 	priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
332 					&drv_data->udev->dev);
333 	if (IS_ERR(priv))
334 		return PTR_ERR(priv);
335 
336 	drv_data->priv = priv;
337 	priv->dev = &drv_data->udev->dev;
338 
339 	usb_set_intfdata(intf, drv_data);
340 
341 	return 0;
342 }
343 
344 static void nfcmrvl_disconnect(struct usb_interface *intf)
345 {
346 	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
347 
348 	if (!drv_data)
349 		return;
350 
351 	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
352 
353 	nfcmrvl_nci_unregister_dev(drv_data->priv);
354 
355 	usb_set_intfdata(drv_data->intf, NULL);
356 }
357 
358 #ifdef CONFIG_PM
359 static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
360 {
361 	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
362 
363 	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
364 
365 	if (drv_data->suspend_count++)
366 		return 0;
367 
368 	spin_lock_irq(&drv_data->txlock);
369 	if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) {
370 		set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
371 		spin_unlock_irq(&drv_data->txlock);
372 	} else {
373 		spin_unlock_irq(&drv_data->txlock);
374 		drv_data->suspend_count--;
375 		return -EBUSY;
376 	}
377 
378 	nfcmrvl_usb_stop_traffic(drv_data);
379 	usb_kill_anchored_urbs(&drv_data->tx_anchor);
380 
381 	return 0;
382 }
383 
384 static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
385 {
386 	struct urb *urb;
387 	int err;
388 
389 	while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
390 		err = usb_submit_urb(urb, GFP_ATOMIC);
391 		if (err)
392 			break;
393 
394 		drv_data->tx_in_flight++;
395 	}
396 	usb_scuttle_anchored_urbs(&drv_data->deferred);
397 }
398 
399 static int nfcmrvl_resume(struct usb_interface *intf)
400 {
401 	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
402 	int err = 0;
403 
404 	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
405 
406 	if (--drv_data->suspend_count)
407 		return 0;
408 
409 	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
410 		goto done;
411 
412 	if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
413 		err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
414 		if (err) {
415 			clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
416 			goto failed;
417 		}
418 
419 		nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
420 	}
421 
422 	spin_lock_irq(&drv_data->txlock);
423 	nfcmrvl_play_deferred(drv_data);
424 	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
425 	spin_unlock_irq(&drv_data->txlock);
426 
427 	return 0;
428 
429 failed:
430 	usb_scuttle_anchored_urbs(&drv_data->deferred);
431 done:
432 	spin_lock_irq(&drv_data->txlock);
433 	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
434 	spin_unlock_irq(&drv_data->txlock);
435 
436 	return err;
437 }
438 #endif
439 
440 static struct usb_driver nfcmrvl_usb_driver = {
441 	.name		= "nfcmrvl",
442 	.probe		= nfcmrvl_probe,
443 	.disconnect	= nfcmrvl_disconnect,
444 #ifdef CONFIG_PM
445 	.suspend	= nfcmrvl_suspend,
446 	.resume		= nfcmrvl_resume,
447 	.reset_resume	= nfcmrvl_resume,
448 #endif
449 	.id_table	= nfcmrvl_table,
450 	.supports_autosuspend = 1,
451 	.disable_hub_initiated_lpm = 1,
452 	.soft_unbind = 1,
453 };
454 module_usb_driver(nfcmrvl_usb_driver);
455 
456 MODULE_AUTHOR("Marvell International Ltd.");
457 MODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION);
458 MODULE_VERSION(VERSION);
459 MODULE_LICENSE("GPL v2");
460