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 static void usb_combined_packet_remove(USBCombinedPacket
*combined
,
37 assert(p
->combined
== combined
);
39 QTAILQ_REMOVE(&combined
->packets
, p
, combined_entry
);
42 /* Also handles completion of non combined packets for pipelined input eps */
43 void usb_combined_input_packet_complete(USBDevice
*dev
, USBPacket
*p
)
45 USBCombinedPacket
*combined
= p
->combined
;
46 USBEndpoint
*ep
= p
->ep
;
48 enum { completing
, complete
, leftover
};
49 int result
, state
= completing
;
52 if (combined
== NULL
) {
53 usb_packet_complete_one(dev
, p
);
57 assert(combined
->first
== p
&& p
== QTAILQ_FIRST(&combined
->packets
));
59 result
= combined
->first
->result
;
60 short_not_ok
= QTAILQ_LAST(&combined
->packets
, packets_head
)->short_not_ok
;
62 QTAILQ_FOREACH_SAFE(p
, &combined
->packets
, combined_entry
, next
) {
63 if (state
== completing
) {
64 /* Distribute data over uncombined packets */
65 if (result
>= p
->iov
.size
) {
66 p
->result
= p
->iov
.size
;
68 /* Send short or error packet to complete the transfer */
72 p
->short_not_ok
= short_not_ok
;
73 usb_combined_packet_remove(combined
, p
);
74 usb_packet_complete_one(dev
, p
);
77 /* Remove any leftover packets from the queue */
79 p
->result
= USB_RET_REMOVE_FROM_QUEUE
;
80 dev
->port
->ops
->complete(dev
->port
, p
);
84 * If we had leftover packets the hcd driver will have cancelled them
85 * and usb_combined_packet_cancel has already freed combined!
87 if (state
!= leftover
) {
91 /* Check if there are packets in the queue waiting for our completion */
92 usb_ep_combine_input_packets(ep
);
95 /* May only be called for combined packets! */
96 void usb_combined_packet_cancel(USBDevice
*dev
, USBPacket
*p
)
98 USBCombinedPacket
*combined
= p
->combined
;
99 assert(combined
!= NULL
);
101 usb_combined_packet_remove(combined
, p
);
102 if (p
== combined
->first
) {
103 usb_device_cancel_packet(dev
, p
);
105 if (QTAILQ_EMPTY(&combined
->packets
)) {
111 * Large input transfers can get split into multiple input packets, this
112 * function recombines them, removing the short_not_ok checks which all but
113 * the last packet of such splits transfers have, thereby allowing input
114 * transfer pipelining (which we cannot do on short_not_ok transfers)
116 void usb_ep_combine_input_packets(USBEndpoint
*ep
)
118 USBPacket
*p
, *u
, *next
, *prev
= NULL
, *first
= NULL
;
119 USBPort
*port
= ep
->dev
->port
;
122 assert(ep
->pipeline
);
123 assert(ep
->pid
== USB_TOKEN_IN
);
125 QTAILQ_FOREACH_SAFE(p
, &ep
->queue
, queue
, next
) {
126 /* Empty the queue on a halt */
128 p
->result
= USB_RET_REMOVE_FROM_QUEUE
;
129 port
->ops
->complete(port
, p
);
133 /* Skip packets already submitted to the device */
134 if (p
->state
== USB_PACKET_ASYNC
) {
138 usb_packet_check_state(p
, USB_PACKET_QUEUED
);
141 * If the previous (combined) packet has the short_not_ok flag set
142 * stop, as we must not submit packets to the device after a transfer
143 * ending with short_not_ok packet.
145 if (prev
&& prev
->short_not_ok
) {
150 if (first
->combined
== NULL
) {
151 USBCombinedPacket
*combined
= g_new0(USBCombinedPacket
, 1);
153 combined
->first
= first
;
154 QTAILQ_INIT(&combined
->packets
);
155 qemu_iovec_init(&combined
->iov
, 2);
156 usb_combined_packet_add(combined
, first
);
158 usb_combined_packet_add(first
->combined
, p
);
163 /* Is this packet the last one of a (combined) transfer? */
164 totalsize
= (p
->combined
) ? p
->combined
->iov
.size
: p
->iov
.size
;
165 if ((p
->iov
.size
% ep
->max_packet_size
) != 0 || !p
->short_not_ok
||
167 /* Work around for Linux usbfs bulk splitting + migration */
168 (totalsize
== 16348 && p
->int_req
)) {
169 ret
= usb_device_handle_data(ep
->dev
, first
);
170 assert(ret
== USB_RET_ASYNC
);
171 if (first
->combined
) {
172 QTAILQ_FOREACH(u
, &first
->combined
->packets
, combined_entry
) {
173 usb_packet_set_state(u
, USB_PACKET_ASYNC
);
176 usb_packet_set_state(first
, USB_PACKET_ASYNC
);