2 * QEMU USB packet combining code (for input pipelining)
4 * Copyright(c) 2012 Red Hat, Inc.
7 * Hans de Goede <hdegoede@redhat.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or(at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "qemu-common.h"
27 static void usb_combined_packet_add(USBCombinedPacket
*combined
, USBPacket
*p
)
29 qemu_iovec_concat(&combined
->iov
, &p
->iov
, 0, p
->iov
.size
);
30 QTAILQ_INSERT_TAIL(&combined
->packets
, p
, combined_entry
);
31 p
->combined
= combined
;
34 /* Note will free combined when the last packet gets removed */
35 static void usb_combined_packet_remove(USBCombinedPacket
*combined
,
38 assert(p
->combined
== combined
);
40 QTAILQ_REMOVE(&combined
->packets
, p
, combined_entry
);
41 if (QTAILQ_EMPTY(&combined
->packets
)) {
42 qemu_iovec_destroy(&combined
->iov
);
47 /* Also handles completion of non combined packets for pipelined input eps */
48 void usb_combined_input_packet_complete(USBDevice
*dev
, USBPacket
*p
)
50 USBCombinedPacket
*combined
= p
->combined
;
51 USBEndpoint
*ep
= p
->ep
;
53 int status
, actual_length
;
54 bool short_not_ok
, done
= false;
56 if (combined
== NULL
) {
57 usb_packet_complete_one(dev
, p
);
61 assert(combined
->first
== p
&& p
== QTAILQ_FIRST(&combined
->packets
));
63 status
= combined
->first
->status
;
64 actual_length
= combined
->first
->actual_length
;
65 short_not_ok
= QTAILQ_LAST(&combined
->packets
, packets_head
)->short_not_ok
;
67 QTAILQ_FOREACH_SAFE(p
, &combined
->packets
, combined_entry
, next
) {
69 /* Distribute data over uncombined packets */
70 if (actual_length
>= p
->iov
.size
) {
71 p
->actual_length
= p
->iov
.size
;
73 /* Send short or error packet to complete the transfer */
74 p
->actual_length
= actual_length
;
77 /* Report status on the last packet */
78 if (done
|| next
== NULL
) {
81 p
->status
= USB_RET_SUCCESS
;
83 p
->short_not_ok
= short_not_ok
;
84 /* Note will free combined when the last packet gets removed! */
85 usb_combined_packet_remove(combined
, p
);
86 usb_packet_complete_one(dev
, p
);
87 actual_length
-= p
->actual_length
;
89 /* Remove any leftover packets from the queue */
90 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
91 /* Note will free combined on the last packet! */
92 dev
->port
->ops
->complete(dev
->port
, p
);
95 /* Do not use combined here, it has been freed! */
97 /* Check if there are packets in the queue waiting for our completion */
98 usb_ep_combine_input_packets(ep
);
101 /* May only be called for combined packets! */
102 void usb_combined_packet_cancel(USBDevice
*dev
, USBPacket
*p
)
104 USBCombinedPacket
*combined
= p
->combined
;
105 assert(combined
!= NULL
);
106 USBPacket
*first
= p
->combined
->first
;
108 /* Note will free combined on the last packet! */
109 usb_combined_packet_remove(combined
, p
);
111 usb_device_cancel_packet(dev
, p
);
116 * Large input transfers can get split into multiple input packets, this
117 * function recombines them, removing the short_not_ok checks which all but
118 * the last packet of such splits transfers have, thereby allowing input
119 * transfer pipelining (which we cannot do on short_not_ok transfers)
121 void usb_ep_combine_input_packets(USBEndpoint
*ep
)
123 USBPacket
*p
, *u
, *next
, *prev
= NULL
, *first
= NULL
;
124 USBPort
*port
= ep
->dev
->port
;
127 assert(ep
->pipeline
);
128 assert(ep
->pid
== USB_TOKEN_IN
);
130 QTAILQ_FOREACH_SAFE(p
, &ep
->queue
, queue
, next
) {
131 /* Empty the queue on a halt */
133 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
134 port
->ops
->complete(port
, p
);
138 /* Skip packets already submitted to the device */
139 if (p
->state
== USB_PACKET_ASYNC
) {
143 usb_packet_check_state(p
, USB_PACKET_QUEUED
);
146 * If the previous (combined) packet has the short_not_ok flag set
147 * stop, as we must not submit packets to the device after a transfer
148 * ending with short_not_ok packet.
150 if (prev
&& prev
->short_not_ok
) {
155 if (first
->combined
== NULL
) {
156 USBCombinedPacket
*combined
= g_new0(USBCombinedPacket
, 1);
158 combined
->first
= first
;
159 QTAILQ_INIT(&combined
->packets
);
160 qemu_iovec_init(&combined
->iov
, 2);
161 usb_combined_packet_add(combined
, first
);
163 usb_combined_packet_add(first
->combined
, p
);
168 /* Is this packet the last one of a (combined) transfer? */
169 totalsize
= (p
->combined
) ? p
->combined
->iov
.size
: p
->iov
.size
;
170 if ((p
->iov
.size
% ep
->max_packet_size
) != 0 || !p
->short_not_ok
||
172 /* Work around for Linux usbfs bulk splitting + migration */
173 (totalsize
== 16348 && p
->int_req
)) {
174 usb_device_handle_data(ep
->dev
, first
);
175 assert(first
->status
== USB_RET_ASYNC
);
176 if (first
->combined
) {
177 QTAILQ_FOREACH(u
, &first
->combined
->packets
, combined_entry
) {
178 usb_packet_set_state(u
, USB_PACKET_ASYNC
);
181 usb_packet_set_state(first
, USB_PACKET_ASYNC
);