Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
  4 * Copyright (C) 2015-2016 Samsung Electronics
  5 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
  6 */
  7
  8#include <net/sock.h>
  9#include <linux/list.h>
 10#include <linux/kthread.h>
 11
 12#include "usbip_common.h"
 13#include "vudc.h"
 14
 15static inline void setup_base_pdu(struct usbip_header_basic *base,
 16				  __u32 command, __u32 seqnum)
 17{
 18	base->command	= command;
 19	base->seqnum	= seqnum;
 20	base->devid	= 0;
 21	base->ep	= 0;
 22	base->direction = 0;
 23}
 24
 25static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urbp *urb_p)
 26{
 27	setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, urb_p->seqnum);
 28	usbip_pack_pdu(rpdu, urb_p->urb, USBIP_RET_SUBMIT, 1);
 29}
 30
 31static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
 32				 struct v_unlink *unlink)
 33{
 34	setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
 35	rpdu->u.ret_unlink.status = unlink->status;
 36}
 37
 38static int v_send_ret_unlink(struct vudc *udc, struct v_unlink *unlink)
 39{
 40	struct msghdr msg;
 41	struct kvec iov[1];
 42	size_t txsize;
 43
 44	int ret;
 45	struct usbip_header pdu_header;
 46
 47	txsize = 0;
 48	memset(&pdu_header, 0, sizeof(pdu_header));
 49	memset(&msg, 0, sizeof(msg));
 50	memset(&iov, 0, sizeof(iov));
 51
 52	/* 1. setup usbip_header */
 53	setup_ret_unlink_pdu(&pdu_header, unlink);
 54	usbip_header_correct_endian(&pdu_header, 1);
 55
 56	iov[0].iov_base = &pdu_header;
 57	iov[0].iov_len  = sizeof(pdu_header);
 58	txsize += sizeof(pdu_header);
 59
 60	ret = kernel_sendmsg(udc->ud.tcp_socket, &msg, iov,
 61			     1, txsize);
 62	if (ret != txsize) {
 63		usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP);
 64		if (ret >= 0)
 65			return -EPIPE;
 66		return ret;
 67	}
 68	kfree(unlink);
 69
 70	return txsize;
 71}
 72
 73static int v_send_ret_submit(struct vudc *udc, struct urbp *urb_p)
 74{
 75	struct urb *urb = urb_p->urb;
 76	struct usbip_header pdu_header;
 77	struct usbip_iso_packet_descriptor *iso_buffer = NULL;
 78	struct kvec *iov = NULL;
 79	int iovnum = 0;
 80	int ret = 0;
 81	size_t txsize;
 82	struct msghdr msg;
 83
 84	txsize = 0;
 85	memset(&pdu_header, 0, sizeof(pdu_header));
 86	memset(&msg, 0, sizeof(msg));
 87
 88	if (urb->actual_length > 0 && !urb->transfer_buffer) {
 89		dev_err(&udc->gadget.dev,
 90			"urb: actual_length %d transfer_buffer null\n",
 91			urb->actual_length);
 92		return -1;
 93	}
 94
 95	if (urb_p->type == USB_ENDPOINT_XFER_ISOC)
 96		iovnum = 2 + urb->number_of_packets;
 97	else
 98		iovnum = 2;
 99
100	iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL);
101	if (!iov) {
102		usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC);
103		ret = -ENOMEM;
104		goto out;
105	}
106	iovnum = 0;
107
108	/* 1. setup usbip_header */
109	setup_ret_submit_pdu(&pdu_header, urb_p);
110	usbip_dbg_stub_tx("setup txdata seqnum: %d\n",
111			  pdu_header.base.seqnum);
112	usbip_header_correct_endian(&pdu_header, 1);
113
114	iov[iovnum].iov_base = &pdu_header;
115	iov[iovnum].iov_len  = sizeof(pdu_header);
116	iovnum++;
117	txsize += sizeof(pdu_header);
118
119	/* 2. setup transfer buffer */
120	if (urb_p->type != USB_ENDPOINT_XFER_ISOC &&
121	    usb_pipein(urb->pipe) && urb->actual_length > 0) {
122		iov[iovnum].iov_base = urb->transfer_buffer;
123		iov[iovnum].iov_len  = urb->actual_length;
124		iovnum++;
125		txsize += urb->actual_length;
126	} else if (urb_p->type == USB_ENDPOINT_XFER_ISOC &&
127		usb_pipein(urb->pipe)) {
128		/* FIXME - copypasted from stub_tx, refactor */
129		int i;
130
131		for (i = 0; i < urb->number_of_packets; i++) {
132			iov[iovnum].iov_base = urb->transfer_buffer +
133				urb->iso_frame_desc[i].offset;
134			iov[iovnum].iov_len =
135				urb->iso_frame_desc[i].actual_length;
136			iovnum++;
137			txsize += urb->iso_frame_desc[i].actual_length;
138		}
139
140		if (txsize != sizeof(pdu_header) + urb->actual_length) {
141			usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP);
142			ret = -EPIPE;
143			goto out;
144		}
145	}
146	/* else - no buffer to send */
147
148	/* 3. setup iso_packet_descriptor */
149	if (urb_p->type == USB_ENDPOINT_XFER_ISOC) {
150		ssize_t len = 0;
151
152		iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
153		if (!iso_buffer) {
154			usbip_event_add(&udc->ud,
155					VUDC_EVENT_ERROR_MALLOC);
156			ret = -ENOMEM;
157			goto out;
158		}
159
160		iov[iovnum].iov_base = iso_buffer;
161		iov[iovnum].iov_len  = len;
162		txsize += len;
163		iovnum++;
164	}
165
166	ret = kernel_sendmsg(udc->ud.tcp_socket, &msg,
167						iov,  iovnum, txsize);
168	if (ret != txsize) {
169		usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP);
170		if (ret >= 0)
171			ret = -EPIPE;
172		goto out;
173	}
174
175out:
176	kfree(iov);
177	kfree(iso_buffer);
178	free_urbp_and_urb(urb_p);
179	if (ret < 0)
180		return ret;
181	return txsize;
182}
183
184static int v_send_ret(struct vudc *udc)
185{
186	unsigned long flags;
187	struct tx_item *txi;
188	size_t total_size = 0;
189	int ret = 0;
190
191	spin_lock_irqsave(&udc->lock_tx, flags);
192	while (!list_empty(&udc->tx_queue)) {
193		txi = list_first_entry(&udc->tx_queue, struct tx_item,
194				       tx_entry);
195		list_del(&txi->tx_entry);
196		spin_unlock_irqrestore(&udc->lock_tx, flags);
197
198		switch (txi->type) {
199		case TX_SUBMIT:
200			ret = v_send_ret_submit(udc, txi->s);
201			break;
202		case TX_UNLINK:
203			ret = v_send_ret_unlink(udc, txi->u);
204			break;
205		}
206		kfree(txi);
207
208		if (ret < 0)
209			return ret;
210
211		total_size += ret;
212
213		spin_lock_irqsave(&udc->lock_tx, flags);
214	}
215
216	spin_unlock_irqrestore(&udc->lock_tx, flags);
217	return total_size;
218}
219
220
221int v_tx_loop(void *data)
222{
223	struct usbip_device *ud = (struct usbip_device *) data;
224	struct vudc *udc = container_of(ud, struct vudc, ud);
225	int ret;
226
227	while (!kthread_should_stop()) {
228		if (usbip_event_happened(&udc->ud))
229			break;
230		ret = v_send_ret(udc);
231		if (ret < 0) {
232			pr_warn("v_tx exit with error %d", ret);
233			break;
234		}
235		wait_event_interruptible(udc->tx_waitq,
236					 (!list_empty(&udc->tx_queue) ||
237					 kthread_should_stop()));
238	}
239
240	return 0;
241}
242
243/* called with spinlocks held */
244void v_enqueue_ret_unlink(struct vudc *udc, __u32 seqnum, __u32 status)
245{
246	struct tx_item *txi;
247	struct v_unlink *unlink;
248
249	txi = kzalloc(sizeof(*txi), GFP_ATOMIC);
250	if (!txi) {
251		usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC);
252		return;
253	}
254	unlink = kzalloc(sizeof(*unlink), GFP_ATOMIC);
255	if (!unlink) {
256		kfree(txi);
257		usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC);
258		return;
259	}
260
261	unlink->seqnum = seqnum;
262	unlink->status = status;
263	txi->type = TX_UNLINK;
264	txi->u = unlink;
265
266	list_add_tail(&txi->tx_entry, &udc->tx_queue);
267}
268
269/* called with spinlocks held */
270void v_enqueue_ret_submit(struct vudc *udc, struct urbp *urb_p)
271{
272	struct tx_item *txi;
273
274	txi = kzalloc(sizeof(*txi), GFP_ATOMIC);
275	if (!txi) {
276		usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC);
277		return;
278	}
279
280	txi->type = TX_SUBMIT;
281	txi->s = urb_p;
282
283	list_add_tail(&txi->tx_entry, &udc->tx_queue);
284}