aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb-bt.c22
-rw-r--r--hw/usb-ccid.c8
-rw-r--r--hw/usb-desc.c71
-rw-r--r--hw/usb-hid.c7
-rw-r--r--hw/usb-hub.c7
-rw-r--r--hw/usb-msd.c10
-rw-r--r--hw/usb-net.c11
-rw-r--r--hw/usb-serial.c7
-rw-r--r--hw/usb-wacom.c7
-rw-r--r--hw/usb.h8
-rw-r--r--trace-events1
-rw-r--r--usb-linux.c10
12 files changed, 90 insertions, 79 deletions
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f30eec1ea2..0c1270be79 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -28,7 +28,6 @@ struct USBBtState {
USBDevice dev;
struct HCIInfo *hci;
- int altsetting;
int config;
#define CFIFO_LEN_MASK 255
@@ -362,7 +361,6 @@ static void usb_bt_handle_reset(USBDevice *dev)
s->outcmd.len = 0;
s->outacl.len = 0;
s->outsco.len = 0;
- s->altsetting = 0;
}
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
@@ -402,26 +400,6 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
case EndpointOutRequest | USB_REQ_SET_FEATURE:
goto fail;
break;
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- if (value != 0 || (index & ~1) || length != 1)
- goto fail;
- if (index == 1)
- data[0] = s->altsetting;
- else
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- if ((index & ~1) || length != 0 ||
- (index == 1 && (value < 0 || value > 4)) ||
- (index == 0 && value != 0)) {
- printf("%s: Wrong SET_INTERFACE request (%i, %i)\n",
- __FUNCTION__, index, value);
- goto fail;
- }
- s->altsetting = value;
- ret = 0;
- break;
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
if (s->config)
usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index cd349f3f17..e9935ad9e6 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -611,14 +611,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
}
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
/* Class specific requests. */
case InterfaceOutClass | CCID_CONTROL_ABORT:
DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index b52561adf8..b9996a1264 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -223,6 +223,54 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
/* ------------------------------------------------------------------ */
+static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
+ int nif, int alt)
+{
+ const USBDescIface *iface;
+ int g, i;
+
+ if (!dev->config) {
+ return NULL;
+ }
+ for (g = 0; g < dev->config->nif_groups; g++) {
+ for (i = 0; i < dev->config->if_groups[g].nif; i++) {
+ iface = &dev->config->if_groups[g].ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ }
+ for (i = 0; i < dev->config->nif; i++) {
+ iface = &dev->config->ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ return NULL;
+}
+
+static int usb_desc_set_interface(USBDevice *dev, int index, int value)
+{
+ const USBDescIface *iface;
+ int old;
+
+ iface = usb_desc_find_interface(dev, index, value);
+ if (iface == NULL) {
+ return -1;
+ }
+
+ old = dev->altsetting[index];
+ dev->altsetting[index] = value;
+ dev->ifaces[index] = iface;
+
+ if (dev->info->set_interface && old != value) {
+ dev->info->set_interface(dev, index, old, value);
+ }
+ return 0;
+}
+
static int usb_desc_set_config(USBDevice *dev, int value)
{
int i;
@@ -237,12 +285,22 @@ static int usb_desc_set_config(USBDevice *dev, int value)
dev->configuration = value;
dev->ninterfaces = dev->device->confs[i].bNumInterfaces;
dev->config = dev->device->confs + i;
+ assert(dev->ninterfaces <= USB_MAX_INTERFACES);
}
}
if (i < dev->device->bNumConfigurations) {
return -1;
}
}
+
+ for (i = 0; i < dev->ninterfaces; i++) {
+ usb_desc_set_interface(dev, i, 0);
+ }
+ for (; i < USB_MAX_INTERFACES; i++) {
+ dev->altsetting[i] = 0;
+ dev->ifaces[i] = NULL;
+ }
+
return 0;
}
@@ -479,6 +537,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
}
trace_usb_set_device_feature(dev->addr, value, ret);
break;
+
+ case InterfaceRequest | USB_REQ_GET_INTERFACE:
+ if (index < 0 || index >= dev->ninterfaces) {
+ break;
+ }
+ data[0] = dev->altsetting[index];
+ ret = 1;
+ break;
+ case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+ ret = usb_desc_set_interface(dev, index, value);
+ trace_usb_set_interface(dev->addr, index, value, ret);
+ break;
+
}
return ret;
}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index a110c74dda..997f8287d8 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -384,13 +384,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
switch (value >> 8) {
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index e1959372e7..069611bbfb 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -258,13 +258,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
}
ret = 0;
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* usb specific requests */
case GetHubStatus:
data[0] = 0;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e42729699d..186831d71b 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -306,19 +306,9 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* Class specific requests. */
case ClassInterfaceOutRequest | MassStorageReset:
/* Reset state ready for the next CBW. */
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f91fa32334..5622bedc45 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1098,17 +1098,6 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
#endif
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
-
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
default:
fail:
fprintf(stderr, "usbnet: failed control transaction: "
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 7dbf6dfc6d..e3c82388ac 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -233,13 +233,6 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 25580067f2..61d5b184df 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -263,13 +263,6 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case WACOM_SET_REPORT:
if (s->mouse_grabbed) {
qemu_remove_mouse_event_handler(s->eh_entry);
diff --git a/hw/usb.h b/hw/usb.h
index 1ef53a102f..1496f7694c 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -161,6 +161,9 @@ struct USBDescString {
QLIST_ENTRY(USBDescString) next;
};
+#define USB_MAX_ENDPOINTS 15
+#define USB_MAX_INTERFACES 16
+
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
@@ -191,7 +194,9 @@ struct USBDevice {
int configuration;
int ninterfaces;
+ int altsetting[USB_MAX_INTERFACES];
const USBDescConfig *config;
+ const USBDescIface *ifaces[USB_MAX_INTERFACES];
};
struct USBDeviceInfo {
@@ -244,6 +249,9 @@ struct USBDeviceInfo {
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
+ void (*set_interface)(USBDevice *dev, int interface,
+ int alt_old, int alt_new);
+
const char *product_desc;
const USBDesc *usb_desc;
diff --git a/trace-events b/trace-events
index c18435bbe1..834eb7f63d 100644
--- a/trace-events
+++ b/trace-events
@@ -246,6 +246,7 @@ usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query
usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
usb_set_addr(int addr) "dev %d"
usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
diff --git a/usb-linux.c b/usb-linux.c
index 3aaa93bd86..ded0726dad 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -544,6 +544,10 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
int interface, nb_interfaces;
int ret, i;
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
+ dev->dev.altsetting[i] = 0;
+ }
+
if (configuration == 0) { /* address state - ignore */
dev->dev.ninterfaces = 0;
dev->dev.configuration = 0;
@@ -997,6 +1001,10 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
}
}
+ if (iface >= USB_MAX_INTERFACES) {
+ return USB_RET_STALL;
+ }
+
si.interface = iface;
si.altsetting = alt;
ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
@@ -1007,6 +1015,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
if (ret < 0) {
return ctrl_error();
}
+
+ s->dev.altsetting[iface] = alt;
usb_linux_update_endp_table(s);
return 0;
}