diff options
-rw-r--r-- | drivers/staging/usbip/stub_tx.c | 74 | ||||
-rw-r--r-- | drivers/staging/usbip/usbip_common.c | 57 | ||||
-rw-r--r-- | drivers/staging/usbip/usbip_common.h | 2 | ||||
-rw-r--r-- | drivers/staging/usbip/vhci_rx.c | 3 |
4 files changed, 122 insertions, 14 deletions
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c index 5523f25998e6..64a52b26dcf6 100644 --- a/drivers/staging/usbip/stub_tx.c +++ b/drivers/staging/usbip/stub_tx.c | |||
@@ -170,7 +170,6 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
170 | struct stub_priv *priv, *tmp; | 170 | struct stub_priv *priv, *tmp; |
171 | 171 | ||
172 | struct msghdr msg; | 172 | struct msghdr msg; |
173 | struct kvec iov[3]; | ||
174 | size_t txsize; | 173 | size_t txsize; |
175 | 174 | ||
176 | size_t total_size = 0; | 175 | size_t total_size = 0; |
@@ -180,28 +179,73 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
180 | struct urb *urb = priv->urb; | 179 | struct urb *urb = priv->urb; |
181 | struct usbip_header pdu_header; | 180 | struct usbip_header pdu_header; |
182 | void *iso_buffer = NULL; | 181 | void *iso_buffer = NULL; |
182 | struct kvec *iov = NULL; | ||
183 | int iovnum = 0; | ||
183 | 184 | ||
184 | txsize = 0; | 185 | txsize = 0; |
185 | memset(&pdu_header, 0, sizeof(pdu_header)); | 186 | memset(&pdu_header, 0, sizeof(pdu_header)); |
186 | memset(&msg, 0, sizeof(msg)); | 187 | memset(&msg, 0, sizeof(msg)); |
187 | memset(&iov, 0, sizeof(iov)); | ||
188 | 188 | ||
189 | usbip_dbg_stub_tx("setup txdata urb %p\n", urb); | 189 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) |
190 | iovnum = 2 + urb->number_of_packets; | ||
191 | else | ||
192 | iovnum = 2; | ||
193 | |||
194 | iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL); | ||
190 | 195 | ||
196 | if (!iov) { | ||
197 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); | ||
198 | return -1; | ||
199 | } | ||
200 | |||
201 | iovnum = 0; | ||
191 | 202 | ||
192 | /* 1. setup usbip_header */ | 203 | /* 1. setup usbip_header */ |
193 | setup_ret_submit_pdu(&pdu_header, urb); | 204 | setup_ret_submit_pdu(&pdu_header, urb); |
205 | usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", | ||
206 | pdu_header.base.seqnum, urb); | ||
207 | /*usbip_dump_header(pdu_header);*/ | ||
194 | usbip_header_correct_endian(&pdu_header, 1); | 208 | usbip_header_correct_endian(&pdu_header, 1); |
195 | 209 | ||
196 | iov[0].iov_base = &pdu_header; | 210 | iov[iovnum].iov_base = &pdu_header; |
197 | iov[0].iov_len = sizeof(pdu_header); | 211 | iov[iovnum].iov_len = sizeof(pdu_header); |
212 | iovnum++; | ||
198 | txsize += sizeof(pdu_header); | 213 | txsize += sizeof(pdu_header); |
199 | 214 | ||
200 | /* 2. setup transfer buffer */ | 215 | /* 2. setup transfer buffer */ |
201 | if (usb_pipein(urb->pipe) && urb->actual_length > 0) { | 216 | if (usb_pipein(urb->pipe) && |
202 | iov[1].iov_base = urb->transfer_buffer; | 217 | usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && |
203 | iov[1].iov_len = urb->actual_length; | 218 | urb->actual_length > 0) { |
219 | iov[iovnum].iov_base = urb->transfer_buffer; | ||
220 | iov[iovnum].iov_len = urb->actual_length; | ||
221 | iovnum++; | ||
204 | txsize += urb->actual_length; | 222 | txsize += urb->actual_length; |
223 | } else if (usb_pipein(urb->pipe) && | ||
224 | usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | ||
225 | /* | ||
226 | * For isochronous packets: actual length is the sum of | ||
227 | * the actual length of the individual, packets, but as | ||
228 | * the packet offsets are not changed there will be | ||
229 | * padding between the packets. To optimally use the | ||
230 | * bandwidth the padding is not transmitted. | ||
231 | */ | ||
232 | |||
233 | int i; | ||
234 | for (i = 0; i < urb->number_of_packets; i++) { | ||
235 | iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
236 | iov[iovnum].iov_len = urb->iso_frame_desc[i].actual_length; | ||
237 | iovnum++; | ||
238 | txsize += urb->iso_frame_desc[i].actual_length; | ||
239 | } | ||
240 | |||
241 | if (txsize != sizeof(pdu_header) + urb->actual_length) { | ||
242 | dev_err(&sdev->interface->dev, | ||
243 | "actual length of urb (%d) does not match iso packet sizes (%d)\n", | ||
244 | urb->actual_length, txsize-sizeof(pdu_header)); | ||
245 | kfree(iov); | ||
246 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | ||
247 | return -1; | ||
248 | } | ||
205 | } | 249 | } |
206 | 250 | ||
207 | /* 3. setup iso_packet_descriptor */ | 251 | /* 3. setup iso_packet_descriptor */ |
@@ -212,32 +256,34 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
212 | if (!iso_buffer) { | 256 | if (!iso_buffer) { |
213 | usbip_event_add(&sdev->ud, | 257 | usbip_event_add(&sdev->ud, |
214 | SDEV_EVENT_ERROR_MALLOC); | 258 | SDEV_EVENT_ERROR_MALLOC); |
259 | kfree(iov); | ||
215 | return -1; | 260 | return -1; |
216 | } | 261 | } |
217 | 262 | ||
218 | iov[2].iov_base = iso_buffer; | 263 | iov[iovnum].iov_base = iso_buffer; |
219 | iov[2].iov_len = len; | 264 | iov[iovnum].iov_len = len; |
220 | txsize += len; | 265 | txsize += len; |
266 | iovnum++; | ||
221 | } | 267 | } |
222 | 268 | ||
223 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, | 269 | ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, |
224 | 3, txsize); | 270 | iov, iovnum, txsize); |
225 | if (ret != txsize) { | 271 | if (ret != txsize) { |
226 | dev_err(&sdev->interface->dev, | 272 | dev_err(&sdev->interface->dev, |
227 | "sendmsg failed!, retval %d for %zd\n", | 273 | "sendmsg failed!, retval %d for %zd\n", |
228 | ret, txsize); | 274 | ret, txsize); |
275 | kfree(iov); | ||
229 | kfree(iso_buffer); | 276 | kfree(iso_buffer); |
230 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); | 277 | usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); |
231 | return -1; | 278 | return -1; |
232 | } | 279 | } |
233 | 280 | ||
281 | kfree(iov); | ||
234 | kfree(iso_buffer); | 282 | kfree(iso_buffer); |
235 | usbip_dbg_stub_tx("send txdata\n"); | ||
236 | 283 | ||
237 | total_size += txsize; | 284 | total_size += txsize; |
238 | } | 285 | } |
239 | 286 | ||
240 | |||
241 | spin_lock_irqsave(&sdev->priv_lock, flags); | 287 | spin_lock_irqsave(&sdev->priv_lock, flags); |
242 | 288 | ||
243 | list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { | 289 | list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { |
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 85622153ea7c..7b1fe45bf7dd 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c | |||
@@ -730,6 +730,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) | |||
730 | int size = np * sizeof(*iso); | 730 | int size = np * sizeof(*iso); |
731 | int i; | 731 | int i; |
732 | int ret; | 732 | int ret; |
733 | int total_length = 0; | ||
733 | 734 | ||
734 | if (!usb_pipeisoc(urb->pipe)) | 735 | if (!usb_pipeisoc(urb->pipe)) |
735 | return 0; | 736 | return 0; |
@@ -759,19 +760,75 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) | |||
759 | return -EPIPE; | 760 | return -EPIPE; |
760 | } | 761 | } |
761 | 762 | ||
763 | |||
762 | for (i = 0; i < np; i++) { | 764 | for (i = 0; i < np; i++) { |
763 | iso = buff + (i * sizeof(*iso)); | 765 | iso = buff + (i * sizeof(*iso)); |
764 | 766 | ||
765 | usbip_iso_pakcet_correct_endian(iso, 0); | 767 | usbip_iso_pakcet_correct_endian(iso, 0); |
766 | usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); | 768 | usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); |
769 | total_length += urb->iso_frame_desc[i].actual_length; | ||
767 | } | 770 | } |
768 | 771 | ||
769 | kfree(buff); | 772 | kfree(buff); |
770 | 773 | ||
774 | if (total_length != urb->actual_length) { | ||
775 | dev_err(&urb->dev->dev, | ||
776 | "total length of iso packets (%d) not equal to actual length of buffer (%d)\n", | ||
777 | total_length, urb->actual_length); | ||
778 | |||
779 | if (ud->side == USBIP_STUB) | ||
780 | usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); | ||
781 | else | ||
782 | usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); | ||
783 | |||
784 | return -EPIPE; | ||
785 | } | ||
786 | |||
771 | return ret; | 787 | return ret; |
772 | } | 788 | } |
773 | EXPORT_SYMBOL_GPL(usbip_recv_iso); | 789 | EXPORT_SYMBOL_GPL(usbip_recv_iso); |
774 | 790 | ||
791 | /* | ||
792 | * This functions restores the padding which was removed for optimizing | ||
793 | * the bandwidth during transfer over tcp/ip | ||
794 | * | ||
795 | * buffer and iso packets need to be stored and be in propeper endian in urb | ||
796 | * before calling this function | ||
797 | */ | ||
798 | int usbip_pad_iso(struct usbip_device *ud, struct urb *urb) | ||
799 | { | ||
800 | int np = urb->number_of_packets; | ||
801 | int i; | ||
802 | int ret; | ||
803 | int actualoffset = urb->actual_length; | ||
804 | |||
805 | if (!usb_pipeisoc(urb->pipe)) | ||
806 | return 0; | ||
807 | |||
808 | /* if no packets or length of data is 0, then nothing to unpack */ | ||
809 | if (np == 0 || urb->actual_length == 0) | ||
810 | return 0; | ||
811 | |||
812 | /* | ||
813 | * if actual_length is transfer_buffer_length then no padding is | ||
814 | * present. | ||
815 | */ | ||
816 | if (urb->actual_length == urb->transfer_buffer_length) | ||
817 | return 0; | ||
818 | |||
819 | /* | ||
820 | * loop over all packets from last to first (to prevent overwritting | ||
821 | * memory when padding) and move them into the proper place | ||
822 | */ | ||
823 | for (i = np-1; i > 0; i--) { | ||
824 | actualoffset -= urb->iso_frame_desc[i].actual_length; | ||
825 | memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, | ||
826 | urb->transfer_buffer + actualoffset, | ||
827 | urb->iso_frame_desc[i].actual_length); | ||
828 | } | ||
829 | return ret; | ||
830 | } | ||
831 | EXPORT_SYMBOL_GPL(usbip_pad_iso); | ||
775 | 832 | ||
776 | /* some members of urb must be substituted before. */ | 833 | /* some members of urb must be substituted before. */ |
777 | int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) | 834 | int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) |
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index 9f809c315d92..c767f52be5fb 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h | |||
@@ -379,6 +379,8 @@ void usbip_header_correct_endian(struct usbip_header *pdu, int send); | |||
379 | int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); | 379 | int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); |
380 | /* some members of urb must be substituted before. */ | 380 | /* some members of urb must be substituted before. */ |
381 | int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); | 381 | int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); |
382 | /* some members of urb must be substituted before. */ | ||
383 | int usbip_pad_iso(struct usbip_device *ud, struct urb *urb); | ||
382 | void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); | 384 | void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); |
383 | 385 | ||
384 | 386 | ||
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 09bf2355934b..2ffc96a4c0d4 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c | |||
@@ -100,6 +100,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, | |||
100 | if (usbip_recv_iso(ud, urb) < 0) | 100 | if (usbip_recv_iso(ud, urb) < 0) |
101 | return; | 101 | return; |
102 | 102 | ||
103 | /* restore the padding in iso packets */ | ||
104 | if (usbip_pad_iso(ud, urb) < 0) | ||
105 | return; | ||
103 | 106 | ||
104 | if (usbip_dbg_flag_vhci_rx) | 107 | if (usbip_dbg_flag_vhci_rx) |
105 | usbip_dump_urb(urb); | 108 | usbip_dump_urb(urb); |