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/osdep.h"
23 #include "qemu-common.h"
28 static void usb_combined_packet_add(USBCombinedPacket
*combined
, USBPacket
*p
)
30 qemu_iovec_concat(&combined
->iov
, &p
->iov
, 0, p
->iov
.size
);
31 QTAILQ_INSERT_TAIL(&combined
->packets
, p
, combined_entry
);
32 p
->combined
= combined
;
35 /* Note will free combined when the last packet gets removed */
36 static void usb_combined_packet_remove(USBCombinedPacket
*combined
,
39 assert(p
->combined
== combined
);
41 QTAILQ_REMOVE(&combined
->packets
, p
, combined_entry
);
42 if (QTAILQ_EMPTY(&combined
->packets
)) {
43 qemu_iovec_destroy(&combined
->iov
);
48 /* Also handles completion of non combined packets for pipelined input eps */
49 void usb_combined_input_packet_complete(USBDevice
*dev
, USBPacket
*p
)
51 USBCombinedPacket
*combined
= p
->combined
;
52 USBEndpoint
*ep
= p
->ep
;
54 int status
, actual_length
;
55 bool short_not_ok
, done
= false;
57 if (combined
== NULL
) {
58 usb_packet_complete_one(dev
, p
);
62 assert(combined
->first
== p
&& p
== QTAILQ_FIRST(&combined
->packets
));
64 status
= combined
->first
->status
;
65 actual_length
= combined
->first
->actual_length
;
66 short_not_ok
= QTAILQ_LAST(&combined
->packets
, packets_head
)->short_not_ok
;
68 QTAILQ_FOREACH_SAFE(p
, &combined
->packets
, combined_entry
, next
) {
70 /* Distribute data over uncombined packets */
71 if (actual_length
>= p
->iov
.size
) {
72 p
->actual_length
= p
->iov
.size
;
74 /* Send short or error packet to complete the transfer */
75 p
->actual_length
= actual_length
;
78 /* Report status on the last packet */
79 if (done
|| next
== NULL
) {
82 p
->status
= USB_RET_SUCCESS
;
84 p
->short_not_ok
= short_not_ok
;
85 /* Note will free combined when the last packet gets removed! */
86 usb_combined_packet_remove(combined
, p
);
87 usb_packet_complete_one(dev
, p
);
88 actual_length
-= p
->actual_length
;
90 /* Remove any leftover packets from the queue */
91 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
92 /* Note will free combined on the last packet! */
93 dev
->port
->ops
->complete(dev
->port
, p
);
96 /* Do not use combined here, it has been freed! */
98 /* Check if there are packets in the queue waiting for our completion */
99 usb_ep_combine_input_packets(ep
);
102 /* May only be called for combined packets! */
103 void usb_combined_packet_cancel(USBDevice
*dev
, USBPacket
*p
)
105 USBCombinedPacket
*combined
= p
->combined
;
106 assert(combined
!= NULL
);
107 USBPacket
*first
= p
->combined
->first
;
109 /* Note will free combined on the last packet! */
110 usb_combined_packet_remove(combined
, p
);
112 usb_device_cancel_packet(dev
, p
);
117 * Large input transfers can get split into multiple input packets, this
118 * function recombines them, removing the short_not_ok checks which all but
119 * the last packet of such splits transfers have, thereby allowing input
120 * transfer pipelining (which we cannot do on short_not_ok transfers)
122 void usb_ep_combine_input_packets(USBEndpoint
*ep
)
124 USBPacket
*p
, *u
, *next
, *prev
= NULL
, *first
= NULL
;
125 USBPort
*port
= ep
->dev
->port
;
128 assert(ep
->pipeline
);
129 assert(ep
->pid
== USB_TOKEN_IN
);
131 QTAILQ_FOREACH_SAFE(p
, &ep
->queue
, queue
, next
) {
132 /* Empty the queue on a halt */
134 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
135 port
->ops
->complete(port
, p
);
139 /* Skip packets already submitted to the device */
140 if (p
->state
== USB_PACKET_ASYNC
) {
144 usb_packet_check_state(p
, USB_PACKET_QUEUED
);
147 * If the previous (combined) packet has the short_not_ok flag set
148 * stop, as we must not submit packets to the device after a transfer
149 * ending with short_not_ok packet.
151 if (prev
&& prev
->short_not_ok
) {
156 if (first
->combined
== NULL
) {
157 USBCombinedPacket
*combined
= g_new0(USBCombinedPacket
, 1);
159 combined
->first
= first
;
160 QTAILQ_INIT(&combined
->packets
);
161 qemu_iovec_init(&combined
->iov
, 2);
162 usb_combined_packet_add(combined
, first
);
164 usb_combined_packet_add(first
->combined
, p
);
169 /* Is this packet the last one of a (combined) transfer? */
170 totalsize
= (p
->combined
) ? p
->combined
->iov
.size
: p
->iov
.size
;
171 if ((p
->iov
.size
% ep
->max_packet_size
) != 0 || !p
->short_not_ok
||
173 /* Work around for Linux usbfs bulk splitting + migration */
174 (totalsize
== 16348 && p
->int_req
)) {
175 usb_device_handle_data(ep
->dev
, first
);
176 assert(first
->status
== USB_RET_ASYNC
);
177 if (first
->combined
) {
178 QTAILQ_FOREACH(u
, &first
->combined
->packets
, combined_entry
) {
179 usb_packet_set_state(u
, USB_PACKET_ASYNC
);
182 usb_packet_set_state(first
, USB_PACKET_ASYNC
);