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.1 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 Lesser General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "qemu/osdep.h"
23 #include "qemu/units.h"
24 #include "qemu-common.h"
29 static void usb_combined_packet_add(USBCombinedPacket
*combined
, USBPacket
*p
)
31 qemu_iovec_concat(&combined
->iov
, &p
->iov
, 0, p
->iov
.size
);
32 QTAILQ_INSERT_TAIL(&combined
->packets
, p
, combined_entry
);
33 p
->combined
= combined
;
36 /* Note will free combined when the last packet gets removed */
37 static void usb_combined_packet_remove(USBCombinedPacket
*combined
,
40 assert(p
->combined
== combined
);
42 QTAILQ_REMOVE(&combined
->packets
, p
, combined_entry
);
43 if (QTAILQ_EMPTY(&combined
->packets
)) {
44 qemu_iovec_destroy(&combined
->iov
);
49 /* Also handles completion of non combined packets for pipelined input eps */
50 void usb_combined_input_packet_complete(USBDevice
*dev
, USBPacket
*p
)
52 USBCombinedPacket
*combined
= p
->combined
;
53 USBEndpoint
*ep
= p
->ep
;
55 int status
, actual_length
;
56 bool short_not_ok
, done
= false;
58 if (combined
== NULL
) {
59 usb_packet_complete_one(dev
, p
);
63 assert(combined
->first
== p
&& p
== QTAILQ_FIRST(&combined
->packets
));
65 status
= combined
->first
->status
;
66 actual_length
= combined
->first
->actual_length
;
67 short_not_ok
= QTAILQ_LAST(&combined
->packets
)->short_not_ok
;
69 QTAILQ_FOREACH_SAFE(p
, &combined
->packets
, combined_entry
, next
) {
71 /* Distribute data over uncombined packets */
72 if (actual_length
>= p
->iov
.size
) {
73 p
->actual_length
= p
->iov
.size
;
75 /* Send short or error packet to complete the transfer */
76 p
->actual_length
= actual_length
;
79 /* Report status on the last packet */
80 if (done
|| next
== NULL
) {
83 p
->status
= USB_RET_SUCCESS
;
85 p
->short_not_ok
= short_not_ok
;
86 /* Note will free combined when the last packet gets removed! */
87 usb_combined_packet_remove(combined
, p
);
88 usb_packet_complete_one(dev
, p
);
89 actual_length
-= p
->actual_length
;
91 /* Remove any leftover packets from the queue */
92 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
93 /* Note will free combined on the last packet! */
94 dev
->port
->ops
->complete(dev
->port
, p
);
97 /* Do not use combined here, it has been freed! */
99 /* Check if there are packets in the queue waiting for our completion */
100 usb_ep_combine_input_packets(ep
);
103 /* May only be called for combined packets! */
104 void usb_combined_packet_cancel(USBDevice
*dev
, USBPacket
*p
)
106 USBCombinedPacket
*combined
= p
->combined
;
107 assert(combined
!= NULL
);
108 USBPacket
*first
= p
->combined
->first
;
110 /* Note will free combined on the last packet! */
111 usb_combined_packet_remove(combined
, p
);
113 usb_device_cancel_packet(dev
, p
);
118 * Large input transfers can get split into multiple input packets, this
119 * function recombines them, removing the short_not_ok checks which all but
120 * the last packet of such splits transfers have, thereby allowing input
121 * transfer pipelining (which we cannot do on short_not_ok transfers)
123 void usb_ep_combine_input_packets(USBEndpoint
*ep
)
125 USBPacket
*p
, *u
, *next
, *prev
= NULL
, *first
= NULL
;
126 USBPort
*port
= ep
->dev
->port
;
129 assert(ep
->pipeline
);
130 assert(ep
->pid
== USB_TOKEN_IN
);
132 QTAILQ_FOREACH_SAFE(p
, &ep
->queue
, queue
, next
) {
133 /* Empty the queue on a halt */
135 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
136 port
->ops
->complete(port
, p
);
140 /* Skip packets already submitted to the device */
141 if (p
->state
== USB_PACKET_ASYNC
) {
145 usb_packet_check_state(p
, USB_PACKET_QUEUED
);
148 * If the previous (combined) packet has the short_not_ok flag set
149 * stop, as we must not submit packets to the device after a transfer
150 * ending with short_not_ok packet.
152 if (prev
&& prev
->short_not_ok
) {
157 if (first
->combined
== NULL
) {
158 USBCombinedPacket
*combined
= g_new0(USBCombinedPacket
, 1);
160 combined
->first
= first
;
161 QTAILQ_INIT(&combined
->packets
);
162 qemu_iovec_init(&combined
->iov
, 2);
163 usb_combined_packet_add(combined
, first
);
165 usb_combined_packet_add(first
->combined
, p
);
170 /* Is this packet the last one of a (combined) transfer? */
171 totalsize
= (p
->combined
) ? p
->combined
->iov
.size
: p
->iov
.size
;
172 if ((p
->iov
.size
% ep
->max_packet_size
) != 0 || !p
->short_not_ok
||
174 /* Work around for Linux usbfs bulk splitting + migration */
175 (totalsize
== (16 * KiB
- 36) && p
->int_req
)) {
176 usb_device_handle_data(ep
->dev
, first
);
177 assert(first
->status
== USB_RET_ASYNC
);
178 if (first
->combined
) {
179 QTAILQ_FOREACH(u
, &first
->combined
->packets
, combined_entry
) {
180 usb_packet_set_state(u
, USB_PACKET_ASYNC
);
183 usb_packet_set_state(first
, USB_PACKET_ASYNC
);