mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'kraxel/usb.70' into staging
* kraxel/usb.70: ehci: fix migration xhci: Fix some DMA host endian bugs usb/combined-packet: Move freeing of combined to usb_combined_packet_remove() xhci: Add support for packets with both data and an error status ehci: Add support for packets with both data and an error status ehci: Get rid of the magical PROC_ERR status usb-redir: Allow packets to have both data and an error-status usb: split packet result into actual_length + status Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#define USB_TOKEN_IN 0x69 /* device -> host */
|
||||
#define USB_TOKEN_OUT 0xe1 /* host -> device */
|
||||
|
||||
#define USB_RET_SUCCESS (0)
|
||||
#define USB_RET_NODEV (-1)
|
||||
#define USB_RET_NAK (-2)
|
||||
#define USB_RET_STALL (-3)
|
||||
@@ -280,18 +281,20 @@ typedef struct USBDeviceClass {
|
||||
* Process control request.
|
||||
* Called from handle_packet().
|
||||
*
|
||||
* Returns length or one of the USB_RET_ codes.
|
||||
* Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
* then the number of bytes transfered is stored in p->actual_length
|
||||
*/
|
||||
int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
|
||||
int index, int length, uint8_t *data);
|
||||
void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
|
||||
int index, int length, uint8_t *data);
|
||||
|
||||
/*
|
||||
* Process data transfers (both BULK and ISOC).
|
||||
* Called from handle_packet().
|
||||
*
|
||||
* Returns length or one of the USB_RET_ codes.
|
||||
* Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
* then the number of bytes transfered is stored in p->actual_length
|
||||
*/
|
||||
int (*handle_data)(USBDevice *dev, USBPacket *p);
|
||||
void (*handle_data)(USBDevice *dev, USBPacket *p);
|
||||
|
||||
void (*set_interface)(USBDevice *dev, int interface,
|
||||
int alt_old, int alt_new);
|
||||
@@ -354,7 +357,8 @@ struct USBPacket {
|
||||
uint64_t parameter; /* control transfers */
|
||||
bool short_not_ok;
|
||||
bool int_req;
|
||||
int result; /* transfer length or USB_RET_* status code */
|
||||
int status; /* USB_RET_* status code */
|
||||
int actual_length; /* Number of bytes actually transfered */
|
||||
/* Internal use by the USB layer. */
|
||||
USBPacketState state;
|
||||
USBCombinedPacket *combined;
|
||||
@@ -388,7 +392,7 @@ static inline bool usb_packet_is_inflight(USBPacket *p)
|
||||
|
||||
USBDevice *usb_find_device(USBPort *port, uint8_t addr);
|
||||
|
||||
int usb_handle_packet(USBDevice *dev, USBPacket *p);
|
||||
void usb_handle_packet(USBDevice *dev, USBPacket *p);
|
||||
void usb_packet_complete(USBDevice *dev, USBPacket *p);
|
||||
void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
|
||||
void usb_cancel_packet(USBPacket * p);
|
||||
@@ -523,10 +527,10 @@ void usb_device_handle_attach(USBDevice *dev);
|
||||
|
||||
void usb_device_handle_reset(USBDevice *dev);
|
||||
|
||||
int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
|
||||
int index, int length, uint8_t *data);
|
||||
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
|
||||
int val, int index, int length, uint8_t *data);
|
||||
|
||||
int usb_device_handle_data(USBDevice *dev, USBPacket *p);
|
||||
void usb_device_handle_data(USBDevice *dev, USBPacket *p);
|
||||
|
||||
void usb_device_set_interface(USBDevice *dev, int interface,
|
||||
int alt_old, int alt_new);
|
||||
|
||||
+5
-8
@@ -140,24 +140,21 @@ void usb_device_handle_reset(USBDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
|
||||
int value, int index, int length, uint8_t *data)
|
||||
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
|
||||
int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_control) {
|
||||
return klass->handle_control(dev, p, request, value, index, length,
|
||||
data);
|
||||
klass->handle_control(dev, p, request, value, index, length, data);
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int usb_device_handle_data(USBDevice *dev, USBPacket *p)
|
||||
void usb_device_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_data) {
|
||||
return klass->handle_data(dev, p);
|
||||
klass->handle_data(dev, p);
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
const char *usb_device_get_product_desc(USBDevice *dev)
|
||||
|
||||
+31
-27
@@ -31,12 +31,16 @@ static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p)
|
||||
p->combined = combined;
|
||||
}
|
||||
|
||||
/* Note will free combined when the last packet gets removed */
|
||||
static void usb_combined_packet_remove(USBCombinedPacket *combined,
|
||||
USBPacket *p)
|
||||
{
|
||||
assert(p->combined == combined);
|
||||
p->combined = NULL;
|
||||
QTAILQ_REMOVE(&combined->packets, p, combined_entry);
|
||||
if (QTAILQ_EMPTY(&combined->packets)) {
|
||||
g_free(combined);
|
||||
}
|
||||
}
|
||||
|
||||
/* Also handles completion of non combined packets for pipelined input eps */
|
||||
@@ -45,9 +49,8 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
USBCombinedPacket *combined = p->combined;
|
||||
USBEndpoint *ep = p->ep;
|
||||
USBPacket *next;
|
||||
enum { completing, complete, leftover };
|
||||
int result, state = completing;
|
||||
bool short_not_ok;
|
||||
int status, actual_length;
|
||||
bool short_not_ok, done = false;
|
||||
|
||||
if (combined == NULL) {
|
||||
usb_packet_complete_one(dev, p);
|
||||
@@ -56,37 +59,39 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
|
||||
assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));
|
||||
|
||||
result = combined->first->result;
|
||||
status = combined->first->status;
|
||||
actual_length = combined->first->actual_length;
|
||||
short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
|
||||
if (state == completing) {
|
||||
if (!done) {
|
||||
/* Distribute data over uncombined packets */
|
||||
if (result >= p->iov.size) {
|
||||
p->result = p->iov.size;
|
||||
if (actual_length >= p->iov.size) {
|
||||
p->actual_length = p->iov.size;
|
||||
} else {
|
||||
/* Send short or error packet to complete the transfer */
|
||||
p->result = result;
|
||||
state = complete;
|
||||
p->actual_length = actual_length;
|
||||
done = true;
|
||||
}
|
||||
/* Report status on the last packet */
|
||||
if (done || next == NULL) {
|
||||
p->status = status;
|
||||
} else {
|
||||
p->status = USB_RET_SUCCESS;
|
||||
}
|
||||
p->short_not_ok = short_not_ok;
|
||||
/* Note will free combined when the last packet gets removed! */
|
||||
usb_combined_packet_remove(combined, p);
|
||||
usb_packet_complete_one(dev, p);
|
||||
result -= p->result;
|
||||
actual_length -= p->actual_length;
|
||||
} else {
|
||||
/* Remove any leftover packets from the queue */
|
||||
state = leftover;
|
||||
p->result = USB_RET_REMOVE_FROM_QUEUE;
|
||||
p->status = USB_RET_REMOVE_FROM_QUEUE;
|
||||
/* Note will free combined on the last packet! */
|
||||
dev->port->ops->complete(dev->port, p);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we had leftover packets the hcd driver will have cancelled them
|
||||
* and usb_combined_packet_cancel has already freed combined!
|
||||
*/
|
||||
if (state != leftover) {
|
||||
g_free(combined);
|
||||
}
|
||||
/* Do not use combined here, it has been freed! */
|
||||
leave:
|
||||
/* Check if there are packets in the queue waiting for our completion */
|
||||
usb_ep_combine_input_packets(ep);
|
||||
@@ -97,14 +102,13 @@ void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBCombinedPacket *combined = p->combined;
|
||||
assert(combined != NULL);
|
||||
USBPacket *first = p->combined->first;
|
||||
|
||||
/* Note will free combined on the last packet! */
|
||||
usb_combined_packet_remove(combined, p);
|
||||
if (p == combined->first) {
|
||||
if (p == first) {
|
||||
usb_device_cancel_packet(dev, p);
|
||||
}
|
||||
if (QTAILQ_EMPTY(&combined->packets)) {
|
||||
g_free(combined);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -117,7 +121,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
|
||||
{
|
||||
USBPacket *p, *u, *next, *prev = NULL, *first = NULL;
|
||||
USBPort *port = ep->dev->port;
|
||||
int ret, totalsize;
|
||||
int totalsize;
|
||||
|
||||
assert(ep->pipeline);
|
||||
assert(ep->pid == USB_TOKEN_IN);
|
||||
@@ -125,7 +129,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
|
||||
QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
|
||||
/* Empty the queue on a halt */
|
||||
if (ep->halted) {
|
||||
p->result = USB_RET_REMOVE_FROM_QUEUE;
|
||||
p->status = USB_RET_REMOVE_FROM_QUEUE;
|
||||
port->ops->complete(port, p);
|
||||
continue;
|
||||
}
|
||||
@@ -166,8 +170,8 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
|
||||
next == NULL ||
|
||||
/* Work around for Linux usbfs bulk splitting + migration */
|
||||
(totalsize == 16348 && p->int_req)) {
|
||||
ret = usb_device_handle_data(ep->dev, first);
|
||||
assert(ret == USB_RET_ASYNC);
|
||||
usb_device_handle_data(ep->dev, first);
|
||||
assert(first->status == USB_RET_ASYNC);
|
||||
if (first->combined) {
|
||||
QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) {
|
||||
usb_packet_set_state(u, USB_PACKET_ASYNC);
|
||||
|
||||
+109
-100
@@ -97,17 +97,17 @@ void usb_wakeup(USBEndpoint *ep)
|
||||
#define SETUP_STATE_ACK 3
|
||||
#define SETUP_STATE_PARAM 4
|
||||
|
||||
static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||
static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
int request, value, index;
|
||||
int ret = 0;
|
||||
|
||||
if (p->iov.size != 8) {
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
||||
p->result = 0;
|
||||
p->actual_length = 0;
|
||||
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
s->setup_index = 0;
|
||||
|
||||
@@ -116,24 +116,26 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||
ret = usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
s->setup_state = SETUP_STATE_SETUP;
|
||||
return USB_RET_ASYNC;
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
s->setup_state = SETUP_STATE_SETUP;
|
||||
}
|
||||
if (p->status != USB_RET_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret < s->setup_len)
|
||||
s->setup_len = ret;
|
||||
if (p->actual_length < s->setup_len) {
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
} else {
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
if (s->setup_len == 0)
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
@@ -141,13 +143,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
}
|
||||
|
||||
return ret;
|
||||
p->actual_length = 8;
|
||||
}
|
||||
|
||||
static int do_token_in(USBDevice *s, USBPacket *p)
|
||||
static void do_token_in(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
int request, value, index;
|
||||
int ret = 0;
|
||||
|
||||
assert(p->ep->nr == 0);
|
||||
|
||||
@@ -158,19 +159,15 @@ static int do_token_in(USBDevice *s, USBPacket *p)
|
||||
switch(s->setup_state) {
|
||||
case SETUP_STATE_ACK:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
ret = usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
return USB_RET_ASYNC;
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
return;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
return ret;
|
||||
p->actual_length = 0;
|
||||
}
|
||||
|
||||
/* return 0 byte */
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SETUP_STATE_DATA:
|
||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||
@@ -180,20 +177,21 @@ static int do_token_in(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
usb_packet_copy(p, s->data_buf + s->setup_index, len);
|
||||
s->setup_index += len;
|
||||
if (s->setup_index >= s->setup_len)
|
||||
if (s->setup_index >= s->setup_len) {
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
return len;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_token_out(USBDevice *s, USBPacket *p)
|
||||
static void do_token_out(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
assert(p->ep->nr == 0);
|
||||
|
||||
@@ -205,7 +203,7 @@ static int do_token_out(USBDevice *s, USBPacket *p)
|
||||
} else {
|
||||
/* ignore additional output */
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SETUP_STATE_DATA:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
@@ -215,23 +213,23 @@ static int do_token_out(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
usb_packet_copy(p, s->data_buf + s->setup_index, len);
|
||||
s->setup_index += len;
|
||||
if (s->setup_index >= s->setup_len)
|
||||
if (s->setup_index >= s->setup_len) {
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
return len;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_parameter(USBDevice *s, USBPacket *p)
|
||||
static void do_parameter(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
int request, value, index;
|
||||
int i, ret = 0;
|
||||
int i, request, value, index;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
s->setup_buf[i] = p->parameter >> (i*8);
|
||||
@@ -249,27 +247,27 @@ static int do_parameter(USBDevice *s, USBPacket *p)
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->pid == USB_TOKEN_OUT) {
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
|
||||
ret = usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < s->setup_len) {
|
||||
s->setup_len = ret;
|
||||
if (p->actual_length < s->setup_len) {
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
p->actual_length = 0;
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ctrl complete function for devices which use usb_generic_handle_packet and
|
||||
@@ -278,30 +276,30 @@ static int do_parameter(USBDevice *s, USBPacket *p)
|
||||
usb_packet_complete to complete their async control packets. */
|
||||
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
if (p->result < 0) {
|
||||
if (p->status < 0) {
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
}
|
||||
|
||||
switch (s->setup_state) {
|
||||
case SETUP_STATE_SETUP:
|
||||
if (p->result < s->setup_len) {
|
||||
s->setup_len = p->result;
|
||||
if (p->actual_length < s->setup_len) {
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
p->result = 8;
|
||||
p->actual_length = 8;
|
||||
break;
|
||||
|
||||
case SETUP_STATE_ACK:
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
p->result = 0;
|
||||
p->actual_length = 0;
|
||||
break;
|
||||
|
||||
case SETUP_STATE_PARAM:
|
||||
if (p->result < s->setup_len) {
|
||||
s->setup_len = p->result;
|
||||
if (p->actual_length < s->setup_len) {
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
p->result = 0;
|
||||
p->actual_length = 0;
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
break;
|
||||
@@ -342,40 +340,57 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr)
|
||||
return usb_device_find_device(dev, addr);
|
||||
}
|
||||
|
||||
static int usb_process_one(USBPacket *p)
|
||||
static void usb_process_one(USBPacket *p)
|
||||
{
|
||||
USBDevice *dev = p->ep->dev;
|
||||
|
||||
/*
|
||||
* Handlers expect status to be initialized to USB_RET_SUCCESS, but it
|
||||
* can be USB_RET_NAK here from a previous usb_process_one() call,
|
||||
* or USB_RET_ASYNC from going through usb_queue_one().
|
||||
*/
|
||||
p->status = USB_RET_SUCCESS;
|
||||
|
||||
if (p->ep->nr == 0) {
|
||||
/* control pipe */
|
||||
if (p->parameter) {
|
||||
return do_parameter(dev, p);
|
||||
do_parameter(dev, p);
|
||||
return;
|
||||
}
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
return do_token_setup(dev, p);
|
||||
do_token_setup(dev, p);
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
return do_token_in(dev, p);
|
||||
do_token_in(dev, p);
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
return do_token_out(dev, p);
|
||||
do_token_out(dev, p);
|
||||
break;
|
||||
default:
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
} else {
|
||||
/* data pipe */
|
||||
return usb_device_handle_data(dev, p);
|
||||
usb_device_handle_data(dev, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hand over a packet to a device for processing. Return value
|
||||
static void usb_queue_one(USBPacket *p)
|
||||
{
|
||||
usb_packet_set_state(p, USB_PACKET_QUEUED);
|
||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
|
||||
/* Hand over a packet to a device for processing. p->status ==
|
||||
USB_RET_ASYNC indicates the processing isn't finished yet, the
|
||||
driver will call usb_packet_complete() when done processing it. */
|
||||
int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
void usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dev == NULL) {
|
||||
return USB_RET_NODEV;
|
||||
p->status = USB_RET_NODEV;
|
||||
return;
|
||||
}
|
||||
assert(dev == p->ep->dev);
|
||||
assert(dev->state == USB_STATE_DEFAULT);
|
||||
@@ -389,32 +404,26 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
|
||||
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
|
||||
ret = usb_process_one(p);
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
usb_process_one(p);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
|
||||
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||
} else if (ret == USB_RET_ADD_TO_QUEUE) {
|
||||
usb_packet_set_state(p, USB_PACKET_QUEUED);
|
||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||
ret = USB_RET_ASYNC;
|
||||
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
|
||||
usb_queue_one(p);
|
||||
} else {
|
||||
/*
|
||||
* When pipelining is enabled usb-devices must always return async,
|
||||
* otherwise packets can complete out of order!
|
||||
*/
|
||||
assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
|
||||
if (ret != USB_RET_NAK) {
|
||||
p->result = ret;
|
||||
if (p->status != USB_RET_NAK) {
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = USB_RET_ASYNC;
|
||||
usb_packet_set_state(p, USB_PACKET_QUEUED);
|
||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||
usb_queue_one(p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
|
||||
@@ -422,9 +431,10 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
|
||||
USBEndpoint *ep = p->ep;
|
||||
|
||||
assert(QTAILQ_FIRST(&ep->queue) == p);
|
||||
assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
|
||||
assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
|
||||
|
||||
if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
|
||||
if (p->status != USB_RET_SUCCESS ||
|
||||
(p->short_not_ok && (p->actual_length < p->iov.size))) {
|
||||
ep->halted = true;
|
||||
}
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
@@ -438,7 +448,6 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
|
||||
void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBEndpoint *ep = p->ep;
|
||||
int ret;
|
||||
|
||||
usb_packet_check_state(p, USB_PACKET_ASYNC);
|
||||
usb_packet_complete_one(dev, p);
|
||||
@@ -447,7 +456,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
p = QTAILQ_FIRST(&ep->queue);
|
||||
if (ep->halted) {
|
||||
/* Empty the queue on a halt */
|
||||
p->result = USB_RET_REMOVE_FROM_QUEUE;
|
||||
p->status = USB_RET_REMOVE_FROM_QUEUE;
|
||||
dev->port->ops->complete(dev->port, p);
|
||||
continue;
|
||||
}
|
||||
@@ -455,12 +464,11 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
break;
|
||||
}
|
||||
usb_packet_check_state(p, USB_PACKET_QUEUED);
|
||||
ret = usb_process_one(p);
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
usb_process_one(p);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
||||
break;
|
||||
}
|
||||
p->result = ret;
|
||||
usb_packet_complete_one(ep->dev, p);
|
||||
}
|
||||
}
|
||||
@@ -541,7 +549,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
|
||||
p->id = id;
|
||||
p->pid = pid;
|
||||
p->ep = ep;
|
||||
p->result = 0;
|
||||
p->status = USB_RET_SUCCESS;
|
||||
p->actual_length = 0;
|
||||
p->parameter = 0;
|
||||
p->short_not_ok = short_not_ok;
|
||||
p->int_req = int_req;
|
||||
@@ -557,31 +566,31 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
|
||||
|
||||
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
|
||||
{
|
||||
assert(p->result >= 0);
|
||||
assert(p->result + bytes <= p->iov.size);
|
||||
assert(p->actual_length >= 0);
|
||||
assert(p->actual_length + bytes <= p->iov.size);
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
case USB_TOKEN_OUT:
|
||||
iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
|
||||
iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
|
||||
iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
|
||||
abort();
|
||||
}
|
||||
p->result += bytes;
|
||||
p->actual_length += bytes;
|
||||
}
|
||||
|
||||
void usb_packet_skip(USBPacket *p, size_t bytes)
|
||||
{
|
||||
assert(p->result >= 0);
|
||||
assert(p->result + bytes <= p->iov.size);
|
||||
assert(p->actual_length >= 0);
|
||||
assert(p->actual_length + bytes <= p->iov.size);
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes);
|
||||
iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
|
||||
}
|
||||
p->result += bytes;
|
||||
p->actual_length += bytes;
|
||||
}
|
||||
|
||||
void usb_packet_cleanup(USBPacket *p)
|
||||
|
||||
+11
-5
@@ -626,7 +626,8 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
|
||||
return pos;
|
||||
}
|
||||
|
||||
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
|
||||
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
||||
int value, uint8_t *dest, size_t len)
|
||||
{
|
||||
const USBDesc *desc = usb_device_get_usb_desc(dev);
|
||||
const USBDescDevice *other_dev;
|
||||
@@ -696,6 +697,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
ret = len;
|
||||
}
|
||||
memcpy(dest, buf, ret);
|
||||
p->actual_length = ret;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -715,7 +718,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
ret = usb_desc_get_descriptor(dev, value, data, length);
|
||||
ret = usb_desc_get_descriptor(dev, p, value, data, length);
|
||||
break;
|
||||
|
||||
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
||||
@@ -724,7 +727,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
||||
* the non zero value of bConfigurationValue.
|
||||
*/
|
||||
data[0] = dev->config ? dev->config->bConfigurationValue : 0;
|
||||
ret = 1;
|
||||
p->actual_length = 1;
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
||||
ret = usb_desc_set_config(dev, value);
|
||||
@@ -749,7 +753,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
||||
data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
|
||||
}
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
p->actual_length = 2;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
@@ -772,7 +777,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
}
|
||||
data[0] = dev->altsetting[index];
|
||||
ret = 1;
|
||||
p->actual_length = 1;
|
||||
ret = 0;
|
||||
break;
|
||||
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
||||
ret = usb_desc_set_interface(dev, index, value);
|
||||
|
||||
+2
-1
@@ -216,7 +216,8 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
|
||||
void usb_desc_create_serial(USBDevice *dev);
|
||||
const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
|
||||
int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
|
||||
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
|
||||
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
||||
int value, uint8_t *dest, size_t len);
|
||||
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data);
|
||||
|
||||
|
||||
+17
-32
@@ -503,7 +503,7 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index,
|
||||
int length, uint8_t *data)
|
||||
{
|
||||
@@ -518,7 +518,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
@@ -534,6 +534,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
p->actual_length = ret;
|
||||
break;
|
||||
|
||||
case ClassInterfaceOutRequest | CR_SET_CUR:
|
||||
@@ -557,10 +558,9 @@ fail:
|
||||
"request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
|
||||
request, value, index, length);
|
||||
}
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_audio_set_interface(USBDevice *dev, int iface,
|
||||
@@ -583,50 +583,35 @@ static void usb_audio_handle_reset(USBDevice *dev)
|
||||
usb_audio_set_output_altset(s, ALTSET_OFF);
|
||||
}
|
||||
|
||||
static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
|
||||
static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (s->out.altset == ALTSET_OFF) {
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
rc = streambuf_put(&s->out.buf, p);
|
||||
if (rc < p->iov.size && s->debug > 1) {
|
||||
streambuf_put(&s->out.buf, p);
|
||||
if (p->actual_length < p->iov.size && s->debug > 1) {
|
||||
fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
|
||||
p->iov.size - rc);
|
||||
p->iov.size - p->actual_length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBAudioState *s = (USBAudioState *) dev;
|
||||
int ret = 0;
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
switch (p->ep->nr) {
|
||||
case 1:
|
||||
ret = usb_audio_handle_dataout(s, p);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
break;
|
||||
if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
|
||||
usb_audio_handle_dataout(s, p);
|
||||
return;
|
||||
}
|
||||
if (ret == USB_RET_STALL && s->debug) {
|
||||
|
||||
p->status = USB_RET_STALL;
|
||||
if (s->debug) {
|
||||
fprintf(stderr, "usb-audio: failed data transaction: "
|
||||
"pid 0x%x ep 0x%x len 0x%zx\n",
|
||||
p->pid, p->ep->nr, p->iov.size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_audio_handle_destroy(USBDevice *dev)
|
||||
|
||||
+14
-19
@@ -285,13 +285,15 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
|
||||
fifo->fifo[off].len = len;
|
||||
}
|
||||
|
||||
static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
|
||||
static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
|
||||
USBPacket *p)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (likely(!fifo->len))
|
||||
return USB_RET_STALL;
|
||||
if (likely(!fifo->len)) {
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
|
||||
usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
|
||||
@@ -310,8 +312,6 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
|
||||
fifo->dstart = 0;
|
||||
fifo->dsize = DFIFO_LEN_MASK + 1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
|
||||
@@ -363,7 +363,7 @@ static void usb_bt_handle_reset(USBDevice *dev)
|
||||
s->outsco.len = 0;
|
||||
}
|
||||
|
||||
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_bt_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
struct USBBtState *s = (struct USBBtState *) dev->opaque;
|
||||
@@ -382,16 +382,15 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
|
||||
usb_bt_fifo_reset(&s->sco);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (request) {
|
||||
case InterfaceRequest | USB_REQ_GET_STATUS:
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
p->actual_length = 2;
|
||||
break;
|
||||
case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
@@ -407,16 +406,14 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
struct USBBtState *s = (struct USBBtState *) dev->opaque;
|
||||
int ret = 0;
|
||||
|
||||
if (!s->config)
|
||||
goto fail;
|
||||
@@ -425,15 +422,15 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
|
||||
case USB_TOKEN_IN:
|
||||
switch (p->ep->nr) {
|
||||
case USB_EVT_EP:
|
||||
ret = usb_bt_fifo_dequeue(&s->evt, p);
|
||||
usb_bt_fifo_dequeue(&s->evt, p);
|
||||
break;
|
||||
|
||||
case USB_ACL_EP:
|
||||
ret = usb_bt_fifo_dequeue(&s->acl, p);
|
||||
usb_bt_fifo_dequeue(&s->acl, p);
|
||||
break;
|
||||
|
||||
case USB_SCO_EP:
|
||||
ret = usb_bt_fifo_dequeue(&s->sco, p);
|
||||
usb_bt_fifo_dequeue(&s->sco, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -460,11 +457,9 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
|
||||
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_bt_out_hci_packet_event(void *opaque,
|
||||
|
||||
+19
-23
@@ -371,7 +371,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
|
||||
hid_reset(&us->hid);
|
||||
}
|
||||
|
||||
static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
|
||||
@@ -380,10 +380,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (request) {
|
||||
/* hid specific requests */
|
||||
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
@@ -392,15 +391,15 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
memcpy(data, qemu_mouse_hid_report_descriptor,
|
||||
sizeof(qemu_mouse_hid_report_descriptor));
|
||||
ret = sizeof(qemu_mouse_hid_report_descriptor);
|
||||
p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
|
||||
} else if (hs->kind == HID_TABLET) {
|
||||
memcpy(data, qemu_tablet_hid_report_descriptor,
|
||||
sizeof(qemu_tablet_hid_report_descriptor));
|
||||
ret = sizeof(qemu_tablet_hid_report_descriptor);
|
||||
p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
memcpy(data, qemu_keyboard_hid_report_descriptor,
|
||||
sizeof(qemu_keyboard_hid_report_descriptor));
|
||||
ret = sizeof(qemu_keyboard_hid_report_descriptor);
|
||||
p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -409,14 +408,14 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
case GET_REPORT:
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
ret = hid_pointer_poll(hs, data, length);
|
||||
p->actual_length = hid_pointer_poll(hs, data, length);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
ret = hid_keyboard_poll(hs, data, length);
|
||||
p->actual_length = hid_keyboard_poll(hs, data, length);
|
||||
}
|
||||
break;
|
||||
case SET_REPORT:
|
||||
if (hs->kind == HID_KEYBOARD) {
|
||||
ret = hid_keyboard_write(hs, data, length);
|
||||
p->actual_length = hid_keyboard_write(hs, data, length);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
@@ -425,19 +424,18 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
|
||||
goto fail;
|
||||
}
|
||||
ret = 1;
|
||||
data[0] = hs->protocol;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
case SET_PROTOCOL:
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
hs->protocol = value;
|
||||
break;
|
||||
case GET_IDLE:
|
||||
ret = 1;
|
||||
data[0] = hs->idle;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
case SET_IDLE:
|
||||
hs->idle = (uint8_t) (value >> 8);
|
||||
@@ -445,22 +443,20 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
hid_pointer_activate(hs);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
|
||||
HIDState *hs = &us->hid;
|
||||
uint8_t buf[p->iov.size];
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
@@ -471,15 +467,16 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
if (!hid_has_events(hs) &&
|
||||
(!hs->idle || hs->next_idle_clock - curtime > 0)) {
|
||||
return USB_RET_NAK;
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
hid_set_next_idle(hs, curtime);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
ret = hid_pointer_poll(hs, buf, p->iov.size);
|
||||
len = hid_pointer_poll(hs, buf, p->iov.size);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
ret = hid_keyboard_poll(hs, buf, p->iov.size);
|
||||
len = hid_keyboard_poll(hs, buf, p->iov.size);
|
||||
}
|
||||
usb_packet_copy(p, buf, ret);
|
||||
usb_packet_copy(p, buf, len);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
@@ -487,10 +484,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_hid_handle_destroy(USBDevice *dev)
|
||||
|
||||
+13
-21
@@ -288,7 +288,7 @@ static const char *feature_name(int feature)
|
||||
return name[feature] ?: "?";
|
||||
}
|
||||
|
||||
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBHubState *s = (USBHubState *)dev;
|
||||
@@ -298,7 +298,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(request) {
|
||||
@@ -306,7 +306,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
if (value == 0 && index != 0x81) { /* clear ep halt */
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
/* usb specific requests */
|
||||
case GetHubStatus:
|
||||
@@ -314,7 +313,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
data[3] = 0;
|
||||
ret = 4;
|
||||
p->actual_length = 4;
|
||||
break;
|
||||
case GetPortStatus:
|
||||
{
|
||||
@@ -331,16 +330,14 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
data[1] = port->wPortStatus >> 8;
|
||||
data[2] = port->wPortChange;
|
||||
data[3] = port->wPortChange >> 8;
|
||||
ret = 4;
|
||||
p->actual_length = 4;
|
||||
}
|
||||
break;
|
||||
case SetHubFeature:
|
||||
case ClearHubFeature:
|
||||
if (value == 0 || value == 1) {
|
||||
} else {
|
||||
if (value != 0 && value != 1) {
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case SetPortFeature:
|
||||
{
|
||||
@@ -373,7 +370,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case ClearPortFeature:
|
||||
@@ -413,7 +409,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case GetHubDescriptor:
|
||||
@@ -437,22 +432,20 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
var_hub_size++;
|
||||
}
|
||||
|
||||
ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
|
||||
data[0] = ret;
|
||||
p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
|
||||
data[0] = p->actual_length;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBHubState *s = (USBHubState *)dev;
|
||||
int ret;
|
||||
|
||||
switch(p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
@@ -465,7 +458,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
|
||||
if (p->iov.size == 1) { /* FreeBSD workaround */
|
||||
n = 1;
|
||||
} else if (n > p->iov.size) {
|
||||
return USB_RET_BABBLE;
|
||||
p->status = USB_RET_BABBLE;
|
||||
return;
|
||||
}
|
||||
status = 0;
|
||||
for(i = 0; i < NUM_PORTS; i++) {
|
||||
@@ -478,9 +472,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
|
||||
buf[i] = status >> (8 * i);
|
||||
}
|
||||
usb_packet_copy(p, buf, n);
|
||||
ret = n;
|
||||
} else {
|
||||
ret = USB_RET_NAK; /* usb11 11.13.1 */
|
||||
p->status = USB_RET_NAK; /* usb11 11.13.1 */
|
||||
}
|
||||
} else {
|
||||
goto fail;
|
||||
@@ -489,10 +482,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_hub_handle_destroy(USBDevice *dev)
|
||||
|
||||
+49
-52
@@ -1048,7 +1048,7 @@ static void usb_net_handle_reset(USBDevice *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBNetState *s = (USBNetState *) dev;
|
||||
@@ -1056,10 +1056,9 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch(request) {
|
||||
case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
|
||||
if (!is_rndis(s) || value || index != 0) {
|
||||
@@ -1078,22 +1077,25 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
||||
}
|
||||
#endif
|
||||
ret = rndis_parse(s, data, length);
|
||||
if (ret < 0) {
|
||||
p->status = ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
|
||||
if (!is_rndis(s) || value || index != 0) {
|
||||
goto fail;
|
||||
}
|
||||
ret = rndis_get_response(s, data);
|
||||
if (!ret) {
|
||||
p->actual_length = rndis_get_response(s, data);
|
||||
if (p->actual_length == 0) {
|
||||
data[0] = 0;
|
||||
ret = 1;
|
||||
p->actual_length = 1;
|
||||
}
|
||||
#ifdef TRAFFIC_DEBUG
|
||||
{
|
||||
unsigned int i;
|
||||
fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
|
||||
for (i = 0; i < ret; i++) {
|
||||
for (i = 0; i < p->actual_length; i++) {
|
||||
if (!(i & 15))
|
||||
fprintf(stderr, "\n%04x:", i);
|
||||
fprintf(stderr, " %02x", data[i]);
|
||||
@@ -1108,72 +1110,67 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
||||
fprintf(stderr, "usbnet: failed control transaction: "
|
||||
"request 0x%x value 0x%x index 0x%x length 0x%x\n",
|
||||
request, value, index, length);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
|
||||
static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
|
||||
{
|
||||
le32 buf[2];
|
||||
int ret = 8;
|
||||
|
||||
if (p->iov.size < 8) {
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
buf[0] = cpu_to_le32(1);
|
||||
buf[1] = cpu_to_le32(0);
|
||||
usb_packet_copy(p, buf, 8);
|
||||
if (!s->rndis_resp.tqh_first)
|
||||
ret = USB_RET_NAK;
|
||||
if (!s->rndis_resp.tqh_first) {
|
||||
p->status = USB_RET_NAK;
|
||||
}
|
||||
|
||||
#ifdef TRAFFIC_DEBUG
|
||||
fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
|
||||
p->iov.size, ret);
|
||||
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
|
||||
p->iov.size, p->status);
|
||||
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
||||
static void usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
||||
{
|
||||
int ret = USB_RET_NAK;
|
||||
int len;
|
||||
|
||||
if (s->in_ptr > s->in_len) {
|
||||
usb_net_reset_in_buf(s);
|
||||
ret = USB_RET_NAK;
|
||||
return ret;
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
if (!s->in_len) {
|
||||
ret = USB_RET_NAK;
|
||||
return ret;
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
ret = s->in_len - s->in_ptr;
|
||||
if (ret > p->iov.size) {
|
||||
ret = p->iov.size;
|
||||
len = s->in_len - s->in_ptr;
|
||||
if (len > p->iov.size) {
|
||||
len = p->iov.size;
|
||||
}
|
||||
usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
|
||||
s->in_ptr += ret;
|
||||
usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
|
||||
s->in_ptr += len;
|
||||
if (s->in_ptr >= s->in_len &&
|
||||
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
|
||||
(is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
|
||||
/* no short packet necessary */
|
||||
usb_net_reset_in_buf(s);
|
||||
}
|
||||
|
||||
#ifdef TRAFFIC_DEBUG
|
||||
fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
|
||||
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
|
||||
fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
|
||||
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
{
|
||||
int ret = p->iov.size;
|
||||
int sz = sizeof(s->out_buf) - s->out_ptr;
|
||||
struct rndis_packet_msg_type *msg =
|
||||
(struct rndis_packet_msg_type *) s->out_buf;
|
||||
@@ -1184,21 +1181,23 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
|
||||
#endif
|
||||
|
||||
if (sz > ret)
|
||||
sz = ret;
|
||||
if (sz > p->iov.size) {
|
||||
sz = p->iov.size;
|
||||
}
|
||||
usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
|
||||
s->out_ptr += sz;
|
||||
|
||||
if (!is_rndis(s)) {
|
||||
if (ret < 64) {
|
||||
if (p->iov.size < 64) {
|
||||
qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
|
||||
s->out_ptr = 0;
|
||||
}
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
len = le32_to_cpu(msg->MessageLength);
|
||||
if (s->out_ptr < 8 || s->out_ptr < len)
|
||||
return ret;
|
||||
if (s->out_ptr < 8 || s->out_ptr < len) {
|
||||
return;
|
||||
}
|
||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
||||
@@ -1207,24 +1206,21 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
}
|
||||
s->out_ptr -= len;
|
||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBNetState *s = (USBNetState *) dev;
|
||||
int ret = 0;
|
||||
|
||||
switch(p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
switch (p->ep->nr) {
|
||||
case 1:
|
||||
ret = usb_net_handle_statusin(s, p);
|
||||
usb_net_handle_statusin(s, p);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ret = usb_net_handle_datain(s, p);
|
||||
usb_net_handle_datain(s, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1235,7 +1231,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
||||
case USB_TOKEN_OUT:
|
||||
switch (p->ep->nr) {
|
||||
case 2:
|
||||
ret = usb_net_handle_dataout(s, p);
|
||||
usb_net_handle_dataout(s, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1245,14 +1241,15 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
||||
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
if (ret == USB_RET_STALL)
|
||||
|
||||
if (p->status == USB_RET_STALL) {
|
||||
fprintf(stderr, "usbnet: failed data transaction: "
|
||||
"pid 0x%x ep 0x%x len 0x%zx\n",
|
||||
p->pid, p->ep->nr, p->iov.size);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
|
||||
+11
-18
@@ -219,7 +219,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBSerialState *s = (USBSerialState *)dev;
|
||||
@@ -228,13 +228,11 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
|
||||
DPRINTF("got control %x, value %x\n",request, value);
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (request) {
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
/* Class specific requests. */
|
||||
@@ -323,7 +321,7 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
|
||||
case DeviceInVendor | FTDI_GET_MDM_ST:
|
||||
data[0] = usb_get_modem_lines(s) | 1;
|
||||
data[1] = 0;
|
||||
ret = 2;
|
||||
p->actual_length = 2;
|
||||
break;
|
||||
case DeviceOutVendor | FTDI_SET_EVENT_CHR:
|
||||
/* TODO: handle it */
|
||||
@@ -338,25 +336,23 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
case DeviceInVendor | FTDI_GET_LATENCY:
|
||||
data[0] = s->latency;
|
||||
ret = 1;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBSerialState *s = (USBSerialState *)dev;
|
||||
int i, ret = 0;
|
||||
uint8_t devep = p->ep->nr;
|
||||
struct iovec *iov;
|
||||
uint8_t header[2];
|
||||
int first_len, len;
|
||||
int i, first_len, len;
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
@@ -366,6 +362,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
iov = p->iov.iov + i;
|
||||
qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
|
||||
}
|
||||
p->actual_length = p->iov.size;
|
||||
break;
|
||||
|
||||
case USB_TOKEN_IN:
|
||||
@@ -374,7 +371,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
first_len = RECV_BUF - s->recv_ptr;
|
||||
len = p->iov.size;
|
||||
if (len <= 2) {
|
||||
ret = USB_RET_NAK;
|
||||
p->status = USB_RET_NAK;
|
||||
break;
|
||||
}
|
||||
header[0] = usb_get_modem_lines(s) | 1;
|
||||
@@ -384,7 +381,6 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
s->event_trigger &= ~FTDI_BI;
|
||||
header[1] = FTDI_BI;
|
||||
usb_packet_copy(p, header, 2);
|
||||
ret = 2;
|
||||
break;
|
||||
} else {
|
||||
header[1] = 0;
|
||||
@@ -393,7 +389,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
if (len > s->recv_used)
|
||||
len = s->recv_used;
|
||||
if (!len) {
|
||||
ret = USB_RET_NAK;
|
||||
p->status = USB_RET_NAK;
|
||||
break;
|
||||
}
|
||||
if (first_len > len)
|
||||
@@ -404,17 +400,14 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
|
||||
usb_packet_copy(p, s->recv_buf, len - first_len);
|
||||
s->recv_used -= len;
|
||||
s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
|
||||
ret = len + 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF("Bad token\n");
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_serial_handle_destroy(USBDevice *dev)
|
||||
|
||||
@@ -635,39 +635,38 @@ static void ccid_handle_reset(USBDevice *dev)
|
||||
ccid_reset(s);
|
||||
}
|
||||
|
||||
static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
|
||||
static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
|
||||
int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
DPRINTF(s, 1, "got control %x, value %x\n", request, value);
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
/* Class specific requests. */
|
||||
case InterfaceOutClass | CCID_CONTROL_ABORT:
|
||||
DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
|
||||
DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES:
|
||||
DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
|
||||
request, value);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ccid_card_inserted(USBCCIDState *s)
|
||||
@@ -870,18 +869,13 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a single USB_TOKEN_OUT, return value returned to guest.
|
||||
* Return value:
|
||||
* 0 - all ok
|
||||
* USB_RET_STALL - failed to handle packet
|
||||
*/
|
||||
static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
|
||||
static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
|
||||
{
|
||||
CCID_Header *ccid_header;
|
||||
|
||||
if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
ccid_header = (CCID_Header *)s->bulk_out_data;
|
||||
usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
|
||||
@@ -890,7 +884,7 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
|
||||
DPRINTF(s, D_VERBOSE,
|
||||
"usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
|
||||
p->iov.size, ccid_header->dwLength);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (s->bulk_out_pos < 10) {
|
||||
DPRINTF(s, 1,
|
||||
@@ -949,60 +943,52 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
|
||||
}
|
||||
}
|
||||
s->bulk_out_pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
|
||||
static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
|
||||
{
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
|
||||
assert(p->iov.size > 0);
|
||||
ccid_bulk_in_get(s);
|
||||
if (s->current_bulk_in != NULL) {
|
||||
ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
|
||||
len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
|
||||
p->iov.size);
|
||||
usb_packet_copy(p, s->current_bulk_in->data +
|
||||
s->current_bulk_in->pos, ret);
|
||||
s->current_bulk_in->pos += ret;
|
||||
s->current_bulk_in->pos, len);
|
||||
s->current_bulk_in->pos += len;
|
||||
if (s->current_bulk_in->pos == s->current_bulk_in->len) {
|
||||
ccid_bulk_in_release(s);
|
||||
}
|
||||
} else {
|
||||
/* return when device has no data - usb 2.0 spec Table 8-4 */
|
||||
ret = USB_RET_NAK;
|
||||
p->status = USB_RET_NAK;
|
||||
}
|
||||
if (ret > 0) {
|
||||
if (len) {
|
||||
DPRINTF(s, D_MORE_INFO,
|
||||
"%s: %zd/%d req/act to guest (BULK_IN)\n",
|
||||
__func__, p->iov.size, ret);
|
||||
__func__, p->iov.size, len);
|
||||
}
|
||||
if (ret != USB_RET_NAK && ret < p->iov.size) {
|
||||
if (len < p->iov.size) {
|
||||
DPRINTF(s, 1,
|
||||
"%s: returning short (EREMOTEIO) %d < %zd\n",
|
||||
__func__, ret, p->iov.size);
|
||||
__func__, len, p->iov.size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ccid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void ccid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
|
||||
int ret = 0;
|
||||
uint8_t buf[2];
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
ret = ccid_handle_bulk_out(s, p);
|
||||
ccid_handle_bulk_out(s, p);
|
||||
break;
|
||||
|
||||
case USB_TOKEN_IN:
|
||||
switch (p->ep->nr) {
|
||||
case CCID_BULK_IN_EP:
|
||||
if (!p->iov.size) {
|
||||
ret = USB_RET_NAK;
|
||||
} else {
|
||||
ret = ccid_bulk_in_copy_to_guest(s, p);
|
||||
}
|
||||
ccid_bulk_in_copy_to_guest(s, p);
|
||||
break;
|
||||
case CCID_INT_IN_EP:
|
||||
if (s->notify_slot_change) {
|
||||
@@ -1010,7 +996,6 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
|
||||
buf[1] = s->bmSlotICCState;
|
||||
usb_packet_copy(p, buf, 2);
|
||||
ret = 2;
|
||||
s->notify_slot_change = false;
|
||||
s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
|
||||
DPRINTF(s, D_INFO,
|
||||
@@ -1021,17 +1006,15 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
break;
|
||||
default:
|
||||
DPRINTF(s, 1, "Bad endpoint\n");
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTF(s, 1, "Bad token\n");
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ccid_handle_destroy(USBDevice *dev)
|
||||
|
||||
+20
-31
@@ -215,7 +215,7 @@ static const USBDesc desc = {
|
||||
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
||||
{
|
||||
uint32_t len;
|
||||
len = p->iov.size - p->result;
|
||||
len = p->iov.size - p->actual_length;
|
||||
if (len > s->scsi_len)
|
||||
len = s->scsi_len;
|
||||
usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
|
||||
@@ -263,7 +263,8 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
|
||||
if (p) {
|
||||
usb_msd_copy_data(s, p);
|
||||
p = s->packet;
|
||||
if (p && p->result == p->iov.size) {
|
||||
if (p && p->actual_length == p->iov.size) {
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
usb_msd_packet_complete(s);
|
||||
}
|
||||
}
|
||||
@@ -292,7 +293,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
|
||||
s->mode = USB_MSDM_CBW;
|
||||
} else {
|
||||
if (s->data_len) {
|
||||
int len = (p->iov.size - p->result);
|
||||
int len = (p->iov.size - p->actual_length);
|
||||
usb_packet_skip(p, len);
|
||||
s->data_len -= len;
|
||||
}
|
||||
@@ -300,6 +301,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
|
||||
s->mode = USB_MSDM_CSW;
|
||||
}
|
||||
}
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
usb_msd_packet_complete(s);
|
||||
} else if (s->data_len == 0) {
|
||||
s->mode = USB_MSDM_CSW;
|
||||
@@ -330,14 +332,14 @@ static void usb_msd_handle_reset(USBDevice *dev)
|
||||
assert(s->req == NULL);
|
||||
|
||||
if (s->packet) {
|
||||
s->packet->result = USB_RET_STALL;
|
||||
s->packet->status = USB_RET_STALL;
|
||||
usb_msd_packet_complete(s);
|
||||
}
|
||||
|
||||
s->mode = USB_MSDM_CBW;
|
||||
}
|
||||
|
||||
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
@@ -345,29 +347,25 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (request) {
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
ret = 0;
|
||||
break;
|
||||
/* Class specific requests. */
|
||||
case ClassInterfaceOutRequest | MassStorageReset:
|
||||
/* Reset state ready for the next CBW. */
|
||||
s->mode = USB_MSDM_CBW;
|
||||
ret = 0;
|
||||
break;
|
||||
case ClassInterfaceRequest | GetMaxLun:
|
||||
data[0] = 0;
|
||||
ret = 1;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
default:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
@@ -382,11 +380,10 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
uint32_t tag;
|
||||
int ret = 0;
|
||||
struct usb_msd_cbw cbw;
|
||||
uint8_t devep = p->ep->nr;
|
||||
|
||||
@@ -433,7 +430,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
|
||||
scsi_req_continue(s->req);
|
||||
}
|
||||
ret = p->result;
|
||||
break;
|
||||
|
||||
case USB_MSDM_DATAOUT:
|
||||
@@ -446,7 +442,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
usb_msd_copy_data(s, p);
|
||||
}
|
||||
if (le32_to_cpu(s->csw.residue)) {
|
||||
int len = p->iov.size - p->result;
|
||||
int len = p->iov.size - p->actual_length;
|
||||
if (len) {
|
||||
usb_packet_skip(p, len);
|
||||
s->data_len -= len;
|
||||
@@ -455,12 +451,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p->result < p->iov.size) {
|
||||
if (p->actual_length < p->iov.size) {
|
||||
DPRINTF("Deferring packet %p [wait data-out]\n", p);
|
||||
s->packet = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
} else {
|
||||
ret = p->result;
|
||||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -481,7 +475,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
/* Waiting for SCSI write to complete. */
|
||||
s->packet = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
p->status = USB_RET_ASYNC;
|
||||
break;
|
||||
|
||||
case USB_MSDM_CSW:
|
||||
@@ -493,11 +487,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
/* still in flight */
|
||||
DPRINTF("Deferring packet %p [wait status]\n", p);
|
||||
s->packet = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
p->status = USB_RET_ASYNC;
|
||||
} else {
|
||||
usb_msd_send_status(s, p);
|
||||
s->mode = USB_MSDM_CBW;
|
||||
ret = 13;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -508,7 +501,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
usb_msd_copy_data(s, p);
|
||||
}
|
||||
if (le32_to_cpu(s->csw.residue)) {
|
||||
int len = p->iov.size - p->result;
|
||||
int len = p->iov.size - p->actual_length;
|
||||
if (len) {
|
||||
usb_packet_skip(p, len);
|
||||
s->data_len -= len;
|
||||
@@ -517,12 +510,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p->result < p->iov.size) {
|
||||
if (p->actual_length < p->iov.size) {
|
||||
DPRINTF("Deferring packet %p [wait data-in]\n", p);
|
||||
s->packet = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
} else {
|
||||
ret = p->result;
|
||||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -535,11 +526,9 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
default:
|
||||
DPRINTF("Bad token\n");
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_msd_password_cb(void *opaque, int err)
|
||||
|
||||
+16
-20
@@ -256,10 +256,10 @@ static void usb_uas_send_status_bh(void *opaque)
|
||||
|
||||
uas->status = NULL;
|
||||
usb_packet_copy(p, &st->status, st->length);
|
||||
p->result = st->length;
|
||||
QTAILQ_REMOVE(&uas->results, st, next);
|
||||
g_free(st);
|
||||
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
usb_packet_complete(&uas->dev, p);
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ static void usb_uas_complete_data_packet(UASRequest *req)
|
||||
p = req->data;
|
||||
req->data = NULL;
|
||||
req->data_async = false;
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
usb_packet_complete(&req->uas->dev, p);
|
||||
}
|
||||
|
||||
@@ -357,16 +358,16 @@ static void usb_uas_copy_data(UASRequest *req)
|
||||
uint32_t length;
|
||||
|
||||
length = MIN(req->buf_size - req->buf_off,
|
||||
req->data->iov.size - req->data->result);
|
||||
req->data->iov.size - req->data->actual_length);
|
||||
trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
|
||||
req->data->result, req->data->iov.size,
|
||||
req->data->actual_length, req->data->iov.size,
|
||||
req->buf_off, req->buf_size);
|
||||
usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
|
||||
length);
|
||||
req->buf_off += length;
|
||||
req->data_off += length;
|
||||
|
||||
if (req->data->result == req->data->iov.size) {
|
||||
if (req->data->actual_length == req->data->iov.size) {
|
||||
usb_uas_complete_data_packet(req);
|
||||
}
|
||||
if (req->buf_size && req->buf_off == req->buf_size) {
|
||||
@@ -504,17 +505,17 @@ static void usb_uas_handle_reset(USBDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_uas_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "%s: unhandled control request\n", __func__);
|
||||
return USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
|
||||
static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
@@ -641,13 +642,13 @@ incorrect_lun:
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0);
|
||||
}
|
||||
|
||||
static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
|
||||
uas_ui ui;
|
||||
UASStatus *st;
|
||||
UASRequest *req;
|
||||
int length, ret = 0;
|
||||
int length;
|
||||
|
||||
switch (p->ep->nr) {
|
||||
case UAS_PIPE_ID_COMMAND:
|
||||
@@ -656,16 +657,14 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
switch (ui.hdr.id) {
|
||||
case UAS_UI_COMMAND:
|
||||
usb_uas_command(uas, &ui);
|
||||
ret = length;
|
||||
break;
|
||||
case UAS_UI_TASK_MGMT:
|
||||
usb_uas_task(uas, &ui);
|
||||
ret = length;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown command ui: id 0x%x\n",
|
||||
__func__, ui.hdr.id);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -674,11 +673,10 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
if (st == NULL) {
|
||||
assert(uas->status == NULL);
|
||||
uas->status = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
p->status = USB_RET_ASYNC;
|
||||
break;
|
||||
}
|
||||
usb_packet_copy(p, &st->status, st->length);
|
||||
ret = st->length;
|
||||
QTAILQ_REMOVE(&uas->results, st, next);
|
||||
g_free(st);
|
||||
break;
|
||||
@@ -687,28 +685,26 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout;
|
||||
if (req == NULL) {
|
||||
fprintf(stderr, "%s: no inflight request\n", __func__);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
scsi_req_ref(req->req);
|
||||
req->data = p;
|
||||
usb_uas_copy_data(req);
|
||||
if (p->result == p->iov.size || req->complete) {
|
||||
if (p->actual_length == p->iov.size || req->complete) {
|
||||
req->data = NULL;
|
||||
ret = p->result;
|
||||
} else {
|
||||
req->data_async = true;
|
||||
ret = USB_RET_ASYNC;
|
||||
p->status = USB_RET_ASYNC;
|
||||
}
|
||||
scsi_req_unref(req->req);
|
||||
usb_uas_start_next_transfer(uas);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr);
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_uas_handle_destroy(USBDevice *dev)
|
||||
|
||||
+17
-21
@@ -250,7 +250,7 @@ static void usb_wacom_handle_reset(USBDevice *dev)
|
||||
s->mode = WACOM_MODE_HID;
|
||||
}
|
||||
|
||||
static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
|
||||
static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data)
|
||||
{
|
||||
USBWacomState *s = (USBWacomState *) dev;
|
||||
@@ -258,10 +258,9 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (request) {
|
||||
case WACOM_SET_REPORT:
|
||||
if (s->mouse_grabbed) {
|
||||
@@ -269,61 +268,58 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
|
||||
s->mouse_grabbed = 0;
|
||||
}
|
||||
s->mode = data[0];
|
||||
ret = 0;
|
||||
break;
|
||||
case WACOM_GET_REPORT:
|
||||
data[0] = 0;
|
||||
data[1] = s->mode;
|
||||
ret = 2;
|
||||
p->actual_length = 2;
|
||||
break;
|
||||
/* USB HID requests */
|
||||
case HID_GET_REPORT:
|
||||
if (s->mode == WACOM_MODE_HID)
|
||||
ret = usb_mouse_poll(s, data, length);
|
||||
p->actual_length = usb_mouse_poll(s, data, length);
|
||||
else if (s->mode == WACOM_MODE_WACOM)
|
||||
ret = usb_wacom_poll(s, data, length);
|
||||
p->actual_length = usb_wacom_poll(s, data, length);
|
||||
break;
|
||||
case HID_GET_IDLE:
|
||||
ret = 1;
|
||||
data[0] = s->idle;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
case HID_SET_IDLE:
|
||||
s->idle = (uint8_t) (value >> 8);
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = USB_RET_STALL;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBWacomState *s = (USBWacomState *) dev;
|
||||
uint8_t buf[p->iov.size];
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
if (p->ep->nr == 1) {
|
||||
if (!(s->changed || s->idle))
|
||||
return USB_RET_NAK;
|
||||
if (!(s->changed || s->idle)) {
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
s->changed = 0;
|
||||
if (s->mode == WACOM_MODE_HID)
|
||||
ret = usb_mouse_poll(s, buf, p->iov.size);
|
||||
len = usb_mouse_poll(s, buf, p->iov.size);
|
||||
else if (s->mode == WACOM_MODE_WACOM)
|
||||
ret = usb_wacom_poll(s, buf, p->iov.size);
|
||||
usb_packet_copy(p, buf, ret);
|
||||
len = usb_wacom_poll(s, buf, p->iov.size);
|
||||
usb_packet_copy(p, buf, len);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
ret = USB_RET_STALL;
|
||||
break;
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_wacom_handle_destroy(USBDevice *dev)
|
||||
|
||||
@@ -91,6 +91,7 @@ static const VMStateDescription vmstate_ehci_pci = {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
|
||||
VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +106,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
|
||||
k->device_id = i->device_id;
|
||||
k->revision = i->revision;
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
dc->vmsd = &vmstate_ehci;
|
||||
dc->vmsd = &vmstate_ehci_pci;
|
||||
dc->props = ehci_pci_properties;
|
||||
}
|
||||
|
||||
|
||||
+104
-112
@@ -29,9 +29,6 @@
|
||||
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
|
||||
/* internal processing - reset HC to try and recover */
|
||||
#define USB_RET_PROCERR (-99)
|
||||
|
||||
/* Capability Registers Base Address - section 2.2 */
|
||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
||||
@@ -1111,7 +1108,7 @@ static int ehci_init_transfer(EHCIPacket *p)
|
||||
while (bytes > 0) {
|
||||
if (cpage > 4) {
|
||||
fprintf(stderr, "cpage out of range (%d)\n", cpage);
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
|
||||
@@ -1129,16 +1126,16 @@ static int ehci_init_transfer(EHCIPacket *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ehci_finish_transfer(EHCIQueue *q, int status)
|
||||
static void ehci_finish_transfer(EHCIQueue *q, int len)
|
||||
{
|
||||
uint32_t cpage, offset;
|
||||
|
||||
if (status > 0) {
|
||||
if (len > 0) {
|
||||
/* update cpage & offset */
|
||||
cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
|
||||
offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
|
||||
|
||||
offset += status;
|
||||
offset += len;
|
||||
cpage += offset >> QTD_BUFPTR_SH;
|
||||
offset &= ~QTD_BUFPTR_MASK;
|
||||
|
||||
@@ -1163,7 +1160,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||
p = container_of(packet, EHCIPacket, packet);
|
||||
assert(p->async == EHCI_ASYNC_INFLIGHT);
|
||||
|
||||
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
|
||||
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
|
||||
trace_usb_ehci_packet_action(p->queue, p, "remove");
|
||||
ehci_free_packet(p);
|
||||
return;
|
||||
@@ -1171,7 +1168,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||
|
||||
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
|
||||
p->async = EHCI_ASYNC_FINISHED;
|
||||
p->usb_status = packet->result;
|
||||
|
||||
if (p->queue->async) {
|
||||
qemu_bh_schedule(p->queue->ehci->async_bh);
|
||||
@@ -1181,58 +1177,60 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||
static void ehci_execute_complete(EHCIQueue *q)
|
||||
{
|
||||
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
|
||||
uint32_t tbytes;
|
||||
|
||||
assert(p != NULL);
|
||||
assert(p->qtdaddr == q->qtdaddr);
|
||||
assert(p->async == EHCI_ASYNC_INITIALIZED ||
|
||||
p->async == EHCI_ASYNC_FINISHED);
|
||||
|
||||
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
|
||||
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
|
||||
DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
|
||||
"status %d, actual_length %d\n",
|
||||
q->qhaddr, q->qh.next, q->qtdaddr,
|
||||
p->packet.status, p->packet.actual_length);
|
||||
|
||||
if (p->usb_status < 0) {
|
||||
switch (p->usb_status) {
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
|
||||
set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_STALL:
|
||||
q->qh.token |= QTD_TOKEN_HALT;
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_NAK:
|
||||
set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
|
||||
return; /* We're not done yet with this transaction */
|
||||
case USB_RET_BABBLE:
|
||||
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
default:
|
||||
/* should not be triggerable */
|
||||
fprintf(stderr, "USB invalid response %d\n", p->usb_status);
|
||||
assert(0);
|
||||
break;
|
||||
switch (p->packet.status) {
|
||||
case USB_RET_SUCCESS:
|
||||
break;
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
|
||||
set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_STALL:
|
||||
q->qh.token |= QTD_TOKEN_HALT;
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_NAK:
|
||||
set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
|
||||
return; /* We're not done yet with this transaction */
|
||||
case USB_RET_BABBLE:
|
||||
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
default:
|
||||
/* should not be triggerable */
|
||||
fprintf(stderr, "USB invalid response %d\n", p->packet.status);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO check 4.12 for splits */
|
||||
tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
|
||||
if (tbytes && p->pid == USB_TOKEN_IN) {
|
||||
tbytes -= p->packet.actual_length;
|
||||
if (tbytes) {
|
||||
/* 4.15.1.2 must raise int on a short input packet */
|
||||
ehci_raise_irq(q->ehci, USBSTS_INT);
|
||||
}
|
||||
} else {
|
||||
// TODO check 4.12 for splits
|
||||
uint32_t tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
|
||||
|
||||
if (tbytes && p->pid == USB_TOKEN_IN) {
|
||||
tbytes -= p->usb_status;
|
||||
if (tbytes) {
|
||||
/* 4.15.1.2 must raise int on a short input packet */
|
||||
ehci_raise_irq(q->ehci, USBSTS_INT);
|
||||
}
|
||||
} else {
|
||||
tbytes = 0;
|
||||
}
|
||||
|
||||
DPRINTF("updating tbytes to %d\n", tbytes);
|
||||
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
|
||||
tbytes = 0;
|
||||
}
|
||||
ehci_finish_transfer(q, p->usb_status);
|
||||
DPRINTF("updating tbytes to %d\n", tbytes);
|
||||
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
|
||||
|
||||
ehci_finish_transfer(q, p->packet.actual_length);
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
p->async = EHCI_ASYNC_NONE;
|
||||
@@ -1248,12 +1246,10 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
}
|
||||
}
|
||||
|
||||
// 4.10.3
|
||||
|
||||
/* 4.10.3 returns "again" */
|
||||
static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
{
|
||||
USBEndpoint *ep;
|
||||
int ret;
|
||||
int endp;
|
||||
bool spd;
|
||||
|
||||
@@ -1262,13 +1258,13 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
|
||||
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||
fprintf(stderr, "Attempting to execute inactive qtd\n");
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
|
||||
ehci_trace_guest_bug(p->queue->ehci,
|
||||
"guest requested more bytes than allowed");
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
|
||||
@@ -1292,7 +1288,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
|
||||
if (p->async == EHCI_ASYNC_NONE) {
|
||||
if (ehci_init_transfer(p) != 0) {
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
|
||||
@@ -1303,17 +1299,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
}
|
||||
|
||||
trace_usb_ehci_packet_action(p->queue, p, action);
|
||||
ret = usb_handle_packet(p->queue->dev, &p->packet);
|
||||
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd endp %x ret %d\n",
|
||||
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
|
||||
q->packet.iov.size, endp, ret);
|
||||
usb_handle_packet(p->queue->dev, &p->packet);
|
||||
DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
|
||||
"status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
|
||||
p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
|
||||
p->packet.actual_length);
|
||||
|
||||
if (ret > BUFF_SIZE) {
|
||||
if (p->packet.actual_length > BUFF_SIZE) {
|
||||
fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 4.7.2
|
||||
@@ -1325,7 +1322,6 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
{
|
||||
USBDevice *dev;
|
||||
USBEndpoint *ep;
|
||||
int ret;
|
||||
uint32_t i, len, pid, dir, devaddr, endp;
|
||||
uint32_t pg, off, ptr1, ptr2, max, mult;
|
||||
|
||||
@@ -1348,7 +1344,7 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
}
|
||||
|
||||
if (len > BUFF_SIZE) {
|
||||
return USB_RET_PROCERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemu_sglist_init(&ehci->isgl, 2, ehci->dma);
|
||||
@@ -1370,45 +1366,45 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
|
||||
(itd->transact[i] & ITD_XACT_IOC) != 0);
|
||||
usb_packet_map(&ehci->ipacket, &ehci->isgl);
|
||||
ret = usb_handle_packet(dev, &ehci->ipacket);
|
||||
usb_handle_packet(dev, &ehci->ipacket);
|
||||
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
|
||||
} else {
|
||||
DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
|
||||
ret = USB_RET_NAK;
|
||||
ehci->ipacket.status = USB_RET_NAK;
|
||||
ehci->ipacket.actual_length = 0;
|
||||
}
|
||||
qemu_sglist_destroy(&ehci->isgl);
|
||||
|
||||
if (ret < 0) {
|
||||
switch (ret) {
|
||||
default:
|
||||
fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
|
||||
/* Fall through */
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
/* 3.3.2: XACTERR is only allowed on IN transactions */
|
||||
if (dir) {
|
||||
itd->transact[i] |= ITD_XACT_XACTERR;
|
||||
ehci_raise_irq(ehci, USBSTS_ERRINT);
|
||||
}
|
||||
break;
|
||||
case USB_RET_BABBLE:
|
||||
itd->transact[i] |= ITD_XACT_BABBLE;
|
||||
switch (ehci->ipacket.status) {
|
||||
case USB_RET_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unexpected iso usb result: %d\n",
|
||||
ehci->ipacket.status);
|
||||
/* Fall through */
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
/* 3.3.2: XACTERR is only allowed on IN transactions */
|
||||
if (dir) {
|
||||
itd->transact[i] |= ITD_XACT_XACTERR;
|
||||
ehci_raise_irq(ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_NAK:
|
||||
/* no data for us, so do a zero-length transfer */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_RET_BABBLE:
|
||||
itd->transact[i] |= ITD_XACT_BABBLE;
|
||||
ehci_raise_irq(ehci, USBSTS_ERRINT);
|
||||
break;
|
||||
case USB_RET_NAK:
|
||||
/* no data for us, so do a zero-length transfer */
|
||||
ehci->ipacket.actual_length = 0;
|
||||
break;
|
||||
}
|
||||
if (ret >= 0) {
|
||||
if (!dir) {
|
||||
/* OUT */
|
||||
set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
|
||||
} else {
|
||||
/* IN */
|
||||
set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
|
||||
}
|
||||
if (!dir) {
|
||||
set_field(&itd->transact[i], len - ehci->ipacket.actual_length,
|
||||
ITD_XACT_LENGTH); /* OUT */
|
||||
} else {
|
||||
set_field(&itd->transact[i], ehci->ipacket.actual_length,
|
||||
ITD_XACT_LENGTH); /* IN */
|
||||
}
|
||||
if (itd->transact[i] & ITD_XACT_IOC) {
|
||||
ehci_raise_irq(ehci, USBSTS_INT);
|
||||
@@ -1746,8 +1742,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
||||
break;
|
||||
case EHCI_ASYNC_INFLIGHT:
|
||||
/* Check if the guest has added new tds to the queue */
|
||||
again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) ==
|
||||
USB_RET_PROCERR) ? -1 : 1;
|
||||
again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
|
||||
/* Unfinished async handled packet, go horizontal */
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
break;
|
||||
@@ -1784,6 +1779,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
|
||||
return again;
|
||||
}
|
||||
|
||||
/* Returns "again" */
|
||||
static int ehci_fill_queue(EHCIPacket *p)
|
||||
{
|
||||
USBEndpoint *ep = p->packet.ep;
|
||||
@@ -1812,17 +1808,14 @@ static int ehci_fill_queue(EHCIPacket *p)
|
||||
p = ehci_alloc_packet(q);
|
||||
p->qtdaddr = qtdaddr;
|
||||
p->qtd = qtd;
|
||||
p->usb_status = ehci_execute(p, "queue");
|
||||
if (p->usb_status == USB_RET_PROCERR) {
|
||||
break;
|
||||
if (ehci_execute(p, "queue") == -1) {
|
||||
return -1;
|
||||
}
|
||||
assert(p->usb_status == USB_RET_ASYNC);
|
||||
assert(p->packet.status == USB_RET_ASYNC);
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
}
|
||||
if (p->usb_status != USB_RET_PROCERR) {
|
||||
usb_device_flush_ep_queue(ep->dev, ep);
|
||||
}
|
||||
return p->usb_status;
|
||||
usb_device_flush_ep_queue(ep->dev, ep);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ehci_state_execute(EHCIQueue *q)
|
||||
@@ -1851,18 +1844,17 @@ static int ehci_state_execute(EHCIQueue *q)
|
||||
ehci_set_usbsts(q->ehci, USBSTS_REC);
|
||||
}
|
||||
|
||||
p->usb_status = ehci_execute(p, "process");
|
||||
if (p->usb_status == USB_RET_PROCERR) {
|
||||
again = -1;
|
||||
again = ehci_execute(p, "process");
|
||||
if (again == -1) {
|
||||
goto out;
|
||||
}
|
||||
if (p->usb_status == USB_RET_ASYNC) {
|
||||
if (p->packet.status == USB_RET_ASYNC) {
|
||||
ehci_flush_qh(q);
|
||||
trace_usb_ehci_packet_action(p->queue, p, "async");
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
if (q->async) {
|
||||
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
|
||||
again = ehci_fill_queue(p);
|
||||
} else {
|
||||
again = 1;
|
||||
}
|
||||
@@ -1891,7 +1883,7 @@ static int ehci_state_executing(EHCIQueue *q)
|
||||
}
|
||||
|
||||
/* 4.10.5 */
|
||||
if (p->usb_status == USB_RET_NAK) {
|
||||
if (p->packet.status == USB_RET_NAK) {
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
} else {
|
||||
ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
|
||||
|
||||
@@ -230,7 +230,6 @@ struct EHCIPacket {
|
||||
QEMUSGList sgl;
|
||||
int pid;
|
||||
enum async_state async;
|
||||
int usb_status;
|
||||
};
|
||||
|
||||
struct EHCIQueue {
|
||||
|
||||
+8
-8
@@ -607,7 +607,6 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
||||
{
|
||||
USBDevice *dev;
|
||||
USBEndpoint *uep;
|
||||
int ret;
|
||||
int idx = epnum && dir;
|
||||
int ttype;
|
||||
|
||||
@@ -632,15 +631,19 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
||||
ep->packey[dir].ep = ep;
|
||||
ep->packey[dir].dir = dir;
|
||||
|
||||
ret = usb_handle_packet(dev, &ep->packey[dir].p);
|
||||
usb_handle_packet(dev, &ep->packey[dir].p);
|
||||
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
if (ep->packey[dir].p.status == USB_RET_ASYNC) {
|
||||
usb_device_flush_ep_queue(dev, uep);
|
||||
ep->status[dir] = len;
|
||||
return;
|
||||
}
|
||||
|
||||
ep->status[dir] = ret;
|
||||
if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
|
||||
ep->status[dir] = ep->packey[dir].p.actual_length;
|
||||
} else {
|
||||
ep->status[dir] = ep->packey[dir].p.status;
|
||||
}
|
||||
musb_schedule_cb(&s->port, &ep->packey[dir].p);
|
||||
}
|
||||
|
||||
@@ -754,7 +757,6 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
|
||||
|
||||
if (ep->status[1] == USB_RET_STALL) {
|
||||
ep->status[1] = 0;
|
||||
packey->result = 0;
|
||||
|
||||
ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
|
||||
if (!epnum)
|
||||
@@ -793,14 +795,12 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
|
||||
/* TODO: check len for over/underruns of an OUT packet? */
|
||||
/* TODO: perhaps make use of e->ext_size[1] here. */
|
||||
|
||||
packey->result = ep->status[1];
|
||||
|
||||
if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
|
||||
ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
|
||||
if (!epnum)
|
||||
ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
|
||||
|
||||
ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
|
||||
ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
|
||||
/* In DMA mode: assert DMA request for this EP */
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user