From 1de14d43e29b8f1fff8bcbf18f300adeb3eabc1d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Aug 2011 13:21:27 +0200 Subject: [PATCH] usb: track altsetting in USBDevice Also handle {GET,SET}_INTERFACE in common code (usb-desc.c). Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 22 --------------- hw/usb-ccid.c | 8 ------ hw/usb-desc.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb-hid.c | 7 ----- hw/usb-hub.c | 7 ----- hw/usb-msd.c | 10 ------- hw/usb-net.c | 11 -------- hw/usb-serial.c | 7 ----- hw/usb-wacom.c | 7 ----- hw/usb.h | 8 ++++++ trace-events | 1 + usb-linux.c | 10 +++++++ 12 files changed, 90 insertions(+), 79 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index f30eec1ea..0c1270be7 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 cd349f3f1..e9935ad9e 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 b52561adf..b9996a126 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 a110c74dd..997f8287d 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 e1959372e..069611bbf 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 e42729699..186831d71 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 f91fa3233..5622bedc4 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 7dbf6dfc6..e3c82388a 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 25580067f..61d5b184d 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 1ef53a102..1496f7694 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 c18435bbe..834eb7f63 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 3aaa93bd8..ded0726da 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; } -- 2.39.2