usb: track altsetting in USBDevice

Also handle {GET,SET}_INTERFACE in common code (usb-desc.c).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2011-08-30 13:21:27 +02:00
parent 65360511a2
commit 1de14d43e2
12 changed files with 90 additions and 79 deletions

View File

@ -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,

View File

@ -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");

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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. */

View File

@ -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: "

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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;
}