/** * stub_complete - completion handler of a usbip urb * @urb: pointer to the urb completed * * When a urb has completed, the USB core driver calls this function mostly in * the interrupt context. To return the result of a urb, the completed urb is * linked to the pending list of returning. *
*/ void stub_complete(struct urb *urb)
{ struct stub_priv *priv = (struct stub_priv *) urb->context; struct stub_device *sdev = priv->sdev; unsignedlong flags;
usbip_dbg_stub_tx("complete! status %d\n", urb->status);
switch (urb->status) { case 0: /* OK */ break; case -ENOENT:
dev_info(&urb->dev->dev, "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n"); return; case -ECONNRESET:
dev_info(&urb->dev->dev, "unlinked by a call to usb_unlink_urb()\n"); break; case -EPIPE:
dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
usb_pipeendpoint(urb->pipe)); break; case -ESHUTDOWN:
dev_info(&urb->dev->dev, "device removed?\n"); break; default:
dev_info(&urb->dev->dev, "urb completion with non-zero status %d\n",
urb->status); break;
}
/* * If the server breaks single SG request into the several URBs, the * URBs must be reassembled before sending completed URB to the vhci. * Don't wake up the tx thread until all the URBs are completed.
*/ if (priv->sgl) {
priv->completed_urbs++;
/* Only save the first error status */ if (urb->status && !priv->urb_status)
priv->urb_status = urb->status;
if (priv->completed_urbs < priv->num_urbs) return;
}
/* link a urb to the queue of tx. */
spin_lock_irqsave(&sdev->priv_lock, flags); if (sdev->ud.tcp_socket == NULL) {
usbip_dbg_stub_tx("ignore urb for closed connection\n"); /* It will be freed in stub_device_cleanup_urbs(). */
} elseif (priv->unlinking) {
stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
stub_free_priv_and_urb(priv);
} else {
list_move_tail(&priv->list, &sdev->priv_tx);
}
spin_unlock_irqrestore(&sdev->priv_lock, flags);
/* wake up tx_thread */
wake_up(&sdev->tx_waitq);
}
/* 2. setup transfer buffer */ if (usb_pipein(urb->pipe) && priv->sgl) { /* If the server split a single SG request into several * URBs because the server's HCD doesn't support SG, * reassemble the split URB buffers into a single * return command.
*/ for (i = 0; i < priv->num_urbs; i++) {
iov[iovnum].iov_base =
priv->urbs[i]->transfer_buffer;
iov[iovnum].iov_len =
priv->urbs[i]->actual_length;
iovnum++;
}
txsize += actual_length;
} elseif (usb_pipein(urb->pipe) &&
usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
urb->actual_length > 0) { if (urb->num_sgs) { unsignedint copy = urb->actual_length; int size;
for_each_sg(urb->sg, sg, urb->num_sgs, i) { if (copy == 0) break;
iovnum++;
copy -= size;
}
} else {
iov[iovnum].iov_base = urb->transfer_buffer;
iov[iovnum].iov_len = urb->actual_length;
iovnum++;
}
txsize += urb->actual_length;
} elseif (usb_pipein(urb->pipe) &&
usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { /* * For isochronous packets: actual length is the sum of * the actual length of the individual, packets, but as * the packet offsets are not changed there will be * padding between the packets. To optimally use the * bandwidth the padding is not transmitted.
*/
int i;
for (i = 0; i < urb->number_of_packets; i++) {
iov[iovnum].iov_base = urb->transfer_buffer +
urb->iso_frame_desc[i].offset;
iov[iovnum].iov_len =
urb->iso_frame_desc[i].actual_length;
iovnum++;
txsize += urb->iso_frame_desc[i].actual_length;
}
if (txsize != sizeof(pdu_header) + urb->actual_length) {
dev_err(&sdev->udev->dev, "actual length of urb %d does not match iso packet sizes %zu\n",
urb->actual_length,
txsize-sizeof(pdu_header));
kfree(iov);
usbip_event_add(&sdev->ud,
SDEV_EVENT_ERROR_TCP); return -1;
}
}
/* 3. setup iso_packet_descriptor */ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
ssize_t len = 0;
while (!kthread_should_stop()) { if (usbip_event_happened(ud)) break;
/* * send_ret_submit comes earlier than send_ret_unlink. stub_rx * looks at only priv_init queue. If the completion of a URB is * earlier than the receive of CMD_UNLINK, priv is moved to * priv_tx queue and stub_rx does not find the target priv. In * this case, vhci_rx receives the result of the submit request * and then receives the result of the unlink request. The * result of the submit is given back to the usbcore as the * completion of the unlink request. The request of the * unlink is ignored. This is ok because a driver who calls * usb_unlink_urb() understands the unlink was too late by * getting the status of the given-backed URB which has the * status of usb_submit_urb().
*/ if (stub_send_ret_submit(sdev) < 0) break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.