diff options
Diffstat (limited to 'drivers/usb/usbip/stub_tx.c')
-rw-r--r-- | drivers/usb/usbip/stub_tx.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c new file mode 100644 index 000000000000..dbcabc9dbe0d --- /dev/null +++ b/drivers/usb/usbip/stub_tx.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003-2008 Takahiro Hirofuchi | ||
3 | * | ||
4 | * This is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | ||
17 | * USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/socket.h> | ||
22 | |||
23 | #include "usbip_common.h" | ||
24 | #include "stub.h" | ||
25 | |||
26 | static void stub_free_priv_and_urb(struct stub_priv *priv) | ||
27 | { | ||
28 | struct urb *urb = priv->urb; | ||
29 | |||
30 | kfree(urb->setup_packet); | ||
31 | kfree(urb->transfer_buffer); | ||
32 | list_del(&priv->list); | ||
33 | kmem_cache_free(stub_priv_cache, priv); | ||
34 | usb_free_urb(urb); | ||
35 | } | ||
36 | |||
37 | /* be in spin_lock_irqsave(&sdev->priv_lock, flags) */ | ||
38 | void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum, | ||
39 | __u32 status) | ||
40 | { | ||
41 | struct stub_unlink *unlink; | ||
42 | |||
43 | unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC); | ||
44 | if (!unlink) { | ||
45 | usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | unlink->seqnum = seqnum; | ||
50 | unlink->status = status; | ||
51 | |||
52 | list_add_tail(&unlink->list, &sdev->unlink_tx); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * stub_complete - completion handler of a usbip urb | ||
57 | * @urb: pointer to the urb completed | ||
58 | * | ||
59 | * When a urb has completed, the USB core driver calls this function mostly in | ||
60 | * the interrupt context. To return the result of a urb, the completed urb is | ||
61 | * linked to the pending list of returning. | ||
62 | * | ||
63 | */ | ||
64 | void stub_complete(struct urb *urb) | ||
65 | { | ||
66 | struct stub_priv *priv = (struct stub_priv *) urb->context; | ||
67 | struct stub_device *sdev = priv->sdev; | ||
68 | unsigned long flags; | ||
69 | |||
70 | usbip_dbg_stub_tx("complete! status %d\n", urb->status); | ||
71 | |||
72 | switch (urb->status) { | ||
73 | case 0: | ||
74 | /* OK */ | ||
75 | break; | ||
76 | case -ENOENT: | ||
77 | dev_info(&urb->dev->dev, | ||
78 | "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n"); | ||
79 | return; | ||
80 | case -ECONNRESET: | ||
81 | dev_info(&urb->dev->dev, | ||
82 | "unlinked by a call to usb_unlink_urb()\n"); | ||
83 | break; | ||
84 | case -EPIPE: | ||
85 | dev_info(&urb->dev->dev, "endpoint %d is stalled\n", | ||
86 | usb_pipeendpoint(urb->pipe)); | ||
87 | break; | ||
88 | case -ESHUTDOWN: | ||
89 | dev_info(&urb->dev->dev, "device removed?\n"); | ||
90 | break; | ||
91 | default: | ||
92 | dev_info(&urb->dev->dev, | ||
93 | "urb completion with non-zero status %d\n", | ||
94 | urb->status); | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | /* link a urb to the queue of tx. */ | ||
99 | spin_lock_irqsave(&sdev->priv_lock, flags); | ||
100 | if (priv->unlinking) { | ||
101 | stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status); | ||
102 | stub_free_priv_and_urb(priv); | ||
103 | } else { | ||
104 | list_move_tail(&priv->list, &sdev->priv_tx); | ||
105 | } | ||
106 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
107 | |||
108 | /* wake up tx_thread */ | ||
109 | wake_up(&sdev->tx_waitq); | ||
110 | } | ||
111 | |||
112 | static inline void setup_base_pdu(struct usbip_header_basic *base, | ||
113 | __u32 command, __u32 seqnum) | ||
114 | { | ||
115 | base->command = command; | ||
116 | base->seqnum = seqnum; | ||
117 | base->devid = 0; | ||
118 | base->ep = 0; | ||
119 | base->direction = 0; | ||
120 | } | ||
121 | |||
122 | static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb) | ||
123 | { | ||
124 | struct stub_priv *priv = (struct stub_priv *) urb->context; | ||
125 | |||
126 | setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum); | ||
127 | usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1); | ||
128 | } | ||
129 | |||
130 | static void setup_ret_unlink_pdu(struct usbip_header *rpdu, | ||
131 | struct stub_unlink *unlink) | ||
132 | { | ||
133 | setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum); | ||
134 | rpdu->u.ret_unlink.status = unlink->status; | ||
135 | } | ||
136 | |||
137 | static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | struct stub_priv *priv, *tmp; | ||
141 | |||
142 | spin_lock_irqsave(&sdev->priv_lock, flags); | ||
143 | |||
144 | list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) { | ||
145 | list_move_tail(&priv->list, &sdev->priv_free); | ||
146 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
147 | return priv; | ||
148 | } | ||
149 | |||
150 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
151 | |||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | static int stub_send_ret_submit(struct stub_device *sdev) | ||
156 | { | ||
157 | unsigned long flags; | ||
158 | struct stub_priv *priv, *tmp; | ||
159 | |||
160 | struct msghdr msg; | ||
161 | size_t txsize; | ||
162 | |||
163 | size_t total_size = 0; | ||
164 | |||
165 | while ((priv = dequeue_from_priv_tx(sdev)) != NULL) { | ||
166 | int ret; | ||
167 | struct urb *urb = priv->urb; | ||
168 | struct usbip_header pdu_header; | ||
169 | struct usbip_iso_packet_descriptor *iso_buffer = NULL; | ||
170 | struct kvec *iov = NULL; | ||
171 | int iovnum = 0; | ||
172 | |||
173 | txsize = 0; | ||
174 | memset(&pdu_header, 0, sizeof(pdu_header)); | ||
175 | memset(&msg, 0, sizeof(msg)); | ||
176 | |||
177 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | ||
178 | iovnum = 2 + urb->number_of_packets; | ||
179 | else | ||
180 | iovnum = 2; | ||
181 | |||
182 | iov = kcalloc(iovnum, sizeof(struct kvec), GFP_KERNEL); | ||
183 | |||
184 | if (!iov) { | ||
185 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); | ||
186 | return -1; | ||
187 | } | ||
188 | |||
189 | iovnum = 0; | ||
190 | |||
191 | /* 1. setup usbip_header */ | ||
192 | setup_ret_submit_pdu(&pdu_header, urb); | ||
193 | usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", | ||
194 | pdu_header.base.seqnum, urb); | ||
195 | usbip_header_correct_endian(&pdu_header, 1); | ||
196 | |||
197 | iov[iovnum].iov_base = &pdu_header; | ||
198 | iov[iovnum].iov_len = sizeof(pdu_header); | ||
199 | iovnum++; | ||
200 | txsize += sizeof(pdu_header); | ||
201 | |||
202 | /* 2. setup transfer buffer */ | ||
203 | if (usb_pipein(urb->pipe) && | ||
204 | usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && | ||
205 | urb->actual_length > 0) { | ||
206 | iov[iovnum].iov_base = urb->transfer_buffer; | ||
207 | iov[iovnum].iov_len = urb->actual_length; | ||
208 | iovnum++; | ||
209 | txsize += urb->actual_length; | ||
210 | } else if (usb_pipein(urb->pipe) && | ||
211 | usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | ||
212 | /* | ||
213 | * For isochronous packets: actual length is the sum of | ||
214 | * the actual length of the individual, packets, but as | ||
215 | * the packet offsets are not changed there will be | ||
216 | * padding between the packets. To optimally use the | ||
217 | * bandwidth the padding is not transmitted. | ||
218 | */ | ||
219 | |||
220 | int i; | ||
221 | |||
222 | for (i = 0; i < urb->number_of_packets; i++) { | ||
223 | iov[iovnum].iov_base = urb->transfer_buffer + | ||
224 | urb->iso_frame_desc[i].offset; | ||
225 | iov[iovnum].iov_len = | ||
226 | urb->iso_frame_desc[i].actual_length; | ||
227 | iovnum++; | ||
228 | txsize += urb->iso_frame_desc[i].actual_length; | ||
229 | } | ||
230 | |||
231 | if (txsize != sizeof(pdu_header) + urb->actual_length) { | ||
232 | dev_err(&sdev->interface->dev, | ||
233 | "actual length of urb %d does not match iso packet sizes %zu\n", | ||
234 | urb->actual_length, | ||
235 | txsize-sizeof(pdu_header)); | ||
236 | kfree(iov); | ||
237 | usbip_event_add(&sdev->ud, | ||
238 | SDEV_EVENT_ERROR_TCP); | ||
239 | return -1; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /* 3. setup iso_packet_descriptor */ | ||
244 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | ||
245 | ssize_t len = 0; | ||
246 | |||
247 | iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len); | ||
248 | if (!iso_buffer) { | ||
249 | usbip_event_add(&sdev->ud, | ||
250 | SDEV_EVENT_ERROR_MALLOC); | ||
251 | kfree(iov); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | iov[iovnum].iov_base = iso_buffer; | ||
256 | iov[iovnum].iov_len = len; | ||
257 | txsize += len; | ||
258 | iovnum++; | ||
259 | } | ||
260 | |||
261 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, | ||
262 | iov, iovnum, txsize); | ||
263 | if (ret != txsize) { | ||
264 | dev_err(&sdev->interface->dev, | ||
265 | "sendmsg failed!, retval %d for %zd\n", | ||
266 | ret, txsize); | ||
267 | kfree(iov); | ||
268 | kfree(iso_buffer); | ||
269 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | ||
270 | return -1; | ||
271 | } | ||
272 | |||
273 | kfree(iov); | ||
274 | kfree(iso_buffer); | ||
275 | |||
276 | total_size += txsize; | ||
277 | } | ||
278 | |||
279 | spin_lock_irqsave(&sdev->priv_lock, flags); | ||
280 | list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { | ||
281 | stub_free_priv_and_urb(priv); | ||
282 | } | ||
283 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
284 | |||
285 | return total_size; | ||
286 | } | ||
287 | |||
288 | static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev) | ||
289 | { | ||
290 | unsigned long flags; | ||
291 | struct stub_unlink *unlink, *tmp; | ||
292 | |||
293 | spin_lock_irqsave(&sdev->priv_lock, flags); | ||
294 | |||
295 | list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) { | ||
296 | list_move_tail(&unlink->list, &sdev->unlink_free); | ||
297 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
298 | return unlink; | ||
299 | } | ||
300 | |||
301 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
302 | |||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | static int stub_send_ret_unlink(struct stub_device *sdev) | ||
307 | { | ||
308 | unsigned long flags; | ||
309 | struct stub_unlink *unlink, *tmp; | ||
310 | |||
311 | struct msghdr msg; | ||
312 | struct kvec iov[1]; | ||
313 | size_t txsize; | ||
314 | |||
315 | size_t total_size = 0; | ||
316 | |||
317 | while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) { | ||
318 | int ret; | ||
319 | struct usbip_header pdu_header; | ||
320 | |||
321 | txsize = 0; | ||
322 | memset(&pdu_header, 0, sizeof(pdu_header)); | ||
323 | memset(&msg, 0, sizeof(msg)); | ||
324 | memset(&iov, 0, sizeof(iov)); | ||
325 | |||
326 | usbip_dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum); | ||
327 | |||
328 | /* 1. setup usbip_header */ | ||
329 | setup_ret_unlink_pdu(&pdu_header, unlink); | ||
330 | usbip_header_correct_endian(&pdu_header, 1); | ||
331 | |||
332 | iov[0].iov_base = &pdu_header; | ||
333 | iov[0].iov_len = sizeof(pdu_header); | ||
334 | txsize += sizeof(pdu_header); | ||
335 | |||
336 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, | ||
337 | 1, txsize); | ||
338 | if (ret != txsize) { | ||
339 | dev_err(&sdev->interface->dev, | ||
340 | "sendmsg failed!, retval %d for %zd\n", | ||
341 | ret, txsize); | ||
342 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | ||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | usbip_dbg_stub_tx("send txdata\n"); | ||
347 | total_size += txsize; | ||
348 | } | ||
349 | |||
350 | spin_lock_irqsave(&sdev->priv_lock, flags); | ||
351 | |||
352 | list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) { | ||
353 | list_del(&unlink->list); | ||
354 | kfree(unlink); | ||
355 | } | ||
356 | |||
357 | spin_unlock_irqrestore(&sdev->priv_lock, flags); | ||
358 | |||
359 | return total_size; | ||
360 | } | ||
361 | |||
362 | int stub_tx_loop(void *data) | ||
363 | { | ||
364 | struct usbip_device *ud = data; | ||
365 | struct stub_device *sdev = container_of(ud, struct stub_device, ud); | ||
366 | |||
367 | while (!kthread_should_stop()) { | ||
368 | if (usbip_event_happened(ud)) | ||
369 | break; | ||
370 | |||
371 | /* | ||
372 | * send_ret_submit comes earlier than send_ret_unlink. stub_rx | ||
373 | * looks at only priv_init queue. If the completion of a URB is | ||
374 | * earlier than the receive of CMD_UNLINK, priv is moved to | ||
375 | * priv_tx queue and stub_rx does not find the target priv. In | ||
376 | * this case, vhci_rx receives the result of the submit request | ||
377 | * and then receives the result of the unlink request. The | ||
378 | * result of the submit is given back to the usbcore as the | ||
379 | * completion of the unlink request. The request of the | ||
380 | * unlink is ignored. This is ok because a driver who calls | ||
381 | * usb_unlink_urb() understands the unlink was too late by | ||
382 | * getting the status of the given-backed URB which has the | ||
383 | * status of usb_submit_urb(). | ||
384 | */ | ||
385 | if (stub_send_ret_submit(sdev) < 0) | ||
386 | break; | ||
387 | |||
388 | if (stub_send_ret_unlink(sdev) < 0) | ||
389 | break; | ||
390 | |||
391 | wait_event_interruptible(sdev->tx_waitq, | ||
392 | (!list_empty(&sdev->priv_tx) || | ||
393 | !list_empty(&sdev->unlink_tx) || | ||
394 | kthread_should_stop())); | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||