mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-21 17:11:57 -06:00
usb-linux: use usb_generic_handle_packet()
Make the linux usb host passthrough code use the usb_generic_handle_packet() function, rather then the curent DYI code. This removes 200 lines of almost identical code. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
007fd62f4d
commit
50b7963e72
3 changed files with 66 additions and 245 deletions
41
hw/usb.c
41
hw/usb.c
|
@ -63,9 +63,10 @@ void usb_wakeup(USBDevice *dev)
|
||||||
protocol)
|
protocol)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SETUP_STATE_IDLE 0
|
#define SETUP_STATE_IDLE 0
|
||||||
#define SETUP_STATE_DATA 1
|
#define SETUP_STATE_SETUP 1
|
||||||
#define SETUP_STATE_ACK 2
|
#define SETUP_STATE_DATA 2
|
||||||
|
#define SETUP_STATE_ACK 3
|
||||||
|
|
||||||
static int do_token_setup(USBDevice *s, USBPacket *p)
|
static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||||
{
|
{
|
||||||
|
@ -86,6 +87,10 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||||
ret = s->info->handle_control(s, p, request, value, index,
|
ret = s->info->handle_control(s, p, request, value, index,
|
||||||
s->setup_len, s->data_buf);
|
s->setup_len, s->data_buf);
|
||||||
|
if (ret == USB_RET_ASYNC) {
|
||||||
|
s->setup_state = SETUP_STATE_SETUP;
|
||||||
|
return USB_RET_ASYNC;
|
||||||
|
}
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -241,6 +246,36 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ctrl complete function for devices which use usb_generic_handle_packet and
|
||||||
|
may return USB_RET_ASYNC from their handle_control callback. Device code
|
||||||
|
which does this *must* call this function instead of the normal
|
||||||
|
usb_packet_complete to complete their async control packets. */
|
||||||
|
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
|
||||||
|
{
|
||||||
|
if (p->len < 0) {
|
||||||
|
s->setup_state = SETUP_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (s->setup_state) {
|
||||||
|
case SETUP_STATE_SETUP:
|
||||||
|
if (p->len < s->setup_len) {
|
||||||
|
s->setup_len = p->len;
|
||||||
|
}
|
||||||
|
s->setup_state = SETUP_STATE_DATA;
|
||||||
|
p->len = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SETUP_STATE_ACK:
|
||||||
|
s->setup_state = SETUP_STATE_IDLE;
|
||||||
|
p->len = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usb_packet_complete(s, p);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: fix overflow */
|
/* XXX: fix overflow */
|
||||||
int set_usb_string(uint8_t *buf, const char *str)
|
int set_usb_string(uint8_t *buf, const char *str)
|
||||||
{
|
{
|
||||||
|
|
1
hw/usb.h
1
hw/usb.h
|
@ -294,6 +294,7 @@ static inline void usb_cancel_packet(USBPacket * p)
|
||||||
void usb_attach(USBPort *port, USBDevice *dev);
|
void usb_attach(USBPort *port, USBDevice *dev);
|
||||||
void usb_wakeup(USBDevice *dev);
|
void usb_wakeup(USBDevice *dev);
|
||||||
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
|
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
|
||||||
|
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
|
||||||
int set_usb_string(uint8_t *buf, const char *str);
|
int set_usb_string(uint8_t *buf, const char *str);
|
||||||
void usb_send_msg(USBDevice *dev, int msg);
|
void usb_send_msg(USBDevice *dev, int msg);
|
||||||
|
|
||||||
|
|
269
usb-linux.c
269
usb-linux.c
|
@ -54,14 +54,6 @@ struct usb_ctrltransfer {
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usb_ctrlrequest {
|
|
||||||
uint8_t bRequestType;
|
|
||||||
uint8_t bRequest;
|
|
||||||
uint16_t wValue;
|
|
||||||
uint16_t wIndex;
|
|
||||||
uint16_t wLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
|
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
|
||||||
int class_id, int vendor_id, int product_id,
|
int class_id, int vendor_id, int product_id,
|
||||||
const char *product_name, int speed);
|
const char *product_name, int speed);
|
||||||
|
@ -108,26 +100,6 @@ struct endp_data {
|
||||||
int max_packet_size;
|
int max_packet_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
CTRL_STATE_IDLE = 0,
|
|
||||||
CTRL_STATE_SETUP,
|
|
||||||
CTRL_STATE_DATA,
|
|
||||||
CTRL_STATE_ACK
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control transfer state.
|
|
||||||
* Note that 'buffer' _must_ follow 'req' field because
|
|
||||||
* we need contiguous buffer when we submit control URB.
|
|
||||||
*/
|
|
||||||
struct ctrl_struct {
|
|
||||||
uint16_t len;
|
|
||||||
uint16_t offset;
|
|
||||||
uint8_t state;
|
|
||||||
struct usb_ctrlrequest req;
|
|
||||||
uint8_t buffer[8192];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct USBAutoFilter {
|
struct USBAutoFilter {
|
||||||
uint32_t bus_num;
|
uint32_t bus_num;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
@ -146,7 +118,6 @@ typedef struct USBHostDevice {
|
||||||
int closing;
|
int closing;
|
||||||
Notifier exit;
|
Notifier exit;
|
||||||
|
|
||||||
struct ctrl_struct ctrl;
|
|
||||||
struct endp_data endp_table[MAX_ENDPOINTS];
|
struct endp_data endp_table[MAX_ENDPOINTS];
|
||||||
|
|
||||||
/* Host side address */
|
/* Host side address */
|
||||||
|
@ -269,26 +240,6 @@ static void async_free(AsyncURB *aurb)
|
||||||
qemu_free(aurb);
|
qemu_free(aurb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
|
|
||||||
{
|
|
||||||
switch(s->ctrl.state) {
|
|
||||||
case CTRL_STATE_SETUP:
|
|
||||||
if (p->len < s->ctrl.len)
|
|
||||||
s->ctrl.len = p->len;
|
|
||||||
s->ctrl.state = CTRL_STATE_DATA;
|
|
||||||
p->len = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTRL_STATE_ACK:
|
|
||||||
s->ctrl.state = CTRL_STATE_IDLE;
|
|
||||||
p->len = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void async_complete(void *opaque)
|
static void async_complete(void *opaque)
|
||||||
{
|
{
|
||||||
USBHostDevice *s = opaque;
|
USBHostDevice *s = opaque;
|
||||||
|
@ -333,9 +284,6 @@ static void async_complete(void *opaque)
|
||||||
switch (aurb->urb.status) {
|
switch (aurb->urb.status) {
|
||||||
case 0:
|
case 0:
|
||||||
p->len = aurb->urb.actual_length;
|
p->len = aurb->urb.actual_length;
|
||||||
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
|
|
||||||
async_complete_ctrl(s, p);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -EPIPE:
|
case -EPIPE:
|
||||||
|
@ -348,7 +296,11 @@ static void async_complete(void *opaque)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_packet_complete(&s->dev, p);
|
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
|
||||||
|
usb_generic_async_ctrl_complete(&s->dev, p);
|
||||||
|
} else {
|
||||||
|
usb_packet_complete(&s->dev, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async_free(aurb);
|
async_free(aurb);
|
||||||
|
@ -675,8 +627,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
|
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
|
||||||
{
|
{
|
||||||
|
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
||||||
struct usbdevfs_urb *urb;
|
struct usbdevfs_urb *urb;
|
||||||
AsyncURB *aurb;
|
AsyncURB *aurb;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -796,45 +749,39 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
|
static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
||||||
|
int request, int value, int index, int length, uint8_t *data)
|
||||||
{
|
{
|
||||||
|
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
||||||
struct usbdevfs_urb *urb;
|
struct usbdevfs_urb *urb;
|
||||||
AsyncURB *aurb;
|
AsyncURB *aurb;
|
||||||
int ret, value, index;
|
int ret;
|
||||||
int buffer_len;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process certain standard device requests.
|
* Process certain standard device requests.
|
||||||
* These are infrequent and are processed synchronously.
|
* These are infrequent and are processed synchronously.
|
||||||
*/
|
*/
|
||||||
value = le16_to_cpu(s->ctrl.req.wValue);
|
|
||||||
index = le16_to_cpu(s->ctrl.req.wIndex);
|
|
||||||
|
|
||||||
|
/* Note request is (bRequestType << 8) | bRequest */
|
||||||
DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
|
DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
|
||||||
s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
|
request >> 8, request & 0xff, value, index, length);
|
||||||
s->ctrl.len);
|
|
||||||
|
|
||||||
if (s->ctrl.req.bRequestType == 0) {
|
switch (request) {
|
||||||
switch (s->ctrl.req.bRequest) {
|
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||||
case USB_REQ_SET_ADDRESS:
|
return usb_host_set_address(s, value);
|
||||||
return usb_host_set_address(s, value);
|
|
||||||
|
|
||||||
case USB_REQ_SET_CONFIGURATION:
|
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
||||||
return usb_host_set_config(s, value & 0xff);
|
return usb_host_set_config(s, value & 0xff);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->ctrl.req.bRequestType == 1 &&
|
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
||||||
s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
|
|
||||||
return usb_host_set_interface(s, index, value);
|
return usb_host_set_interface(s, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The rest are asynchronous */
|
/* The rest are asynchronous */
|
||||||
|
|
||||||
buffer_len = 8 + s->ctrl.len;
|
if (length > sizeof(dev->data_buf)) {
|
||||||
if (buffer_len > sizeof(s->ctrl.buffer)) {
|
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
|
||||||
fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
|
length, sizeof(dev->data_buf));
|
||||||
buffer_len, sizeof(s->ctrl.buffer));
|
|
||||||
return USB_RET_STALL;
|
return USB_RET_STALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,8 +800,8 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
|
||||||
urb->type = USBDEVFS_URB_TYPE_CONTROL;
|
urb->type = USBDEVFS_URB_TYPE_CONTROL;
|
||||||
urb->endpoint = p->devep;
|
urb->endpoint = p->devep;
|
||||||
|
|
||||||
urb->buffer = &s->ctrl.req;
|
urb->buffer = &dev->setup_buf;
|
||||||
urb->buffer_length = buffer_len;
|
urb->buffer_length = length + 8;
|
||||||
|
|
||||||
urb->usercontext = s;
|
urb->usercontext = s;
|
||||||
|
|
||||||
|
@ -879,170 +826,6 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_token_setup(USBDevice *dev, USBPacket *p)
|
|
||||||
{
|
|
||||||
USBHostDevice *s = (USBHostDevice *) dev;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (p->len != 8) {
|
|
||||||
return USB_RET_STALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&s->ctrl.req, p->data, 8);
|
|
||||||
s->ctrl.len = le16_to_cpu(s->ctrl.req.wLength);
|
|
||||||
s->ctrl.offset = 0;
|
|
||||||
s->ctrl.state = CTRL_STATE_SETUP;
|
|
||||||
|
|
||||||
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
|
|
||||||
ret = usb_host_handle_control(s, p);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < s->ctrl.len) {
|
|
||||||
s->ctrl.len = ret;
|
|
||||||
}
|
|
||||||
s->ctrl.state = CTRL_STATE_DATA;
|
|
||||||
} else {
|
|
||||||
if (s->ctrl.len == 0) {
|
|
||||||
s->ctrl.state = CTRL_STATE_ACK;
|
|
||||||
} else {
|
|
||||||
s->ctrl.state = CTRL_STATE_DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_token_in(USBDevice *dev, USBPacket *p)
|
|
||||||
{
|
|
||||||
USBHostDevice *s = (USBHostDevice *) dev;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (p->devep != 0) {
|
|
||||||
return usb_host_handle_data(s, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(s->ctrl.state) {
|
|
||||||
case CTRL_STATE_ACK:
|
|
||||||
if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
|
|
||||||
ret = usb_host_handle_control(s, p);
|
|
||||||
if (ret == USB_RET_ASYNC) {
|
|
||||||
return USB_RET_ASYNC;
|
|
||||||
}
|
|
||||||
s->ctrl.state = CTRL_STATE_IDLE;
|
|
||||||
return ret > 0 ? 0 : ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case CTRL_STATE_DATA:
|
|
||||||
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
|
|
||||||
int len = s->ctrl.len - s->ctrl.offset;
|
|
||||||
if (len > p->len) {
|
|
||||||
len = p->len;
|
|
||||||
}
|
|
||||||
memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
|
|
||||||
s->ctrl.offset += len;
|
|
||||||
if (s->ctrl.offset >= s->ctrl.len) {
|
|
||||||
s->ctrl.state = CTRL_STATE_ACK;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->ctrl.state = CTRL_STATE_IDLE;
|
|
||||||
return USB_RET_STALL;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return USB_RET_STALL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_token_out(USBDevice *dev, USBPacket *p)
|
|
||||||
{
|
|
||||||
USBHostDevice *s = (USBHostDevice *) dev;
|
|
||||||
|
|
||||||
if (p->devep != 0) {
|
|
||||||
return usb_host_handle_data(s, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(s->ctrl.state) {
|
|
||||||
case CTRL_STATE_ACK:
|
|
||||||
if (s->ctrl.req.bRequestType & USB_DIR_IN) {
|
|
||||||
s->ctrl.state = CTRL_STATE_IDLE;
|
|
||||||
/* transfer OK */
|
|
||||||
} else {
|
|
||||||
/* ignore additional output */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case CTRL_STATE_DATA:
|
|
||||||
if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
|
|
||||||
int len = s->ctrl.len - s->ctrl.offset;
|
|
||||||
if (len > p->len) {
|
|
||||||
len = p->len;
|
|
||||||
}
|
|
||||||
memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
|
|
||||||
s->ctrl.offset += len;
|
|
||||||
if (s->ctrl.offset >= s->ctrl.len) {
|
|
||||||
s->ctrl.state = CTRL_STATE_ACK;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->ctrl.state = CTRL_STATE_IDLE;
|
|
||||||
return USB_RET_STALL;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return USB_RET_STALL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Packet handler.
|
|
||||||
* Called by the HC (host controller).
|
|
||||||
*
|
|
||||||
* Returns length of the transaction or one of the USB_RET_XXX codes.
|
|
||||||
*/
|
|
||||||
static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
|
|
||||||
{
|
|
||||||
switch(p->pid) {
|
|
||||||
case USB_MSG_ATTACH:
|
|
||||||
s->state = USB_STATE_ATTACHED;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case USB_MSG_DETACH:
|
|
||||||
s->state = USB_STATE_NOTATTACHED;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case USB_MSG_RESET:
|
|
||||||
s->remote_wakeup = 0;
|
|
||||||
s->addr = 0;
|
|
||||||
s->state = USB_STATE_DEFAULT;
|
|
||||||
s->info->handle_reset(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rest of the PIDs must match our address */
|
|
||||||
if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
|
|
||||||
return USB_RET_NODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (p->pid) {
|
|
||||||
case USB_TOKEN_SETUP:
|
|
||||||
return do_token_setup(s, p);
|
|
||||||
|
|
||||||
case USB_TOKEN_IN:
|
|
||||||
return do_token_in(s, p);
|
|
||||||
|
|
||||||
case USB_TOKEN_OUT:
|
|
||||||
return do_token_out(s, p);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return USB_RET_STALL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usb_linux_get_configuration(USBHostDevice *s)
|
static int usb_linux_get_configuration(USBHostDevice *s)
|
||||||
{
|
{
|
||||||
uint8_t configuration;
|
uint8_t configuration;
|
||||||
|
@ -1368,7 +1151,9 @@ static struct USBDeviceInfo usb_host_dev_info = {
|
||||||
.qdev.name = "usb-host",
|
.qdev.name = "usb-host",
|
||||||
.qdev.size = sizeof(USBHostDevice),
|
.qdev.size = sizeof(USBHostDevice),
|
||||||
.init = usb_host_initfn,
|
.init = usb_host_initfn,
|
||||||
.handle_packet = usb_host_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
|
.handle_data = usb_host_handle_data,
|
||||||
|
.handle_control = usb_host_handle_control,
|
||||||
.handle_reset = usb_host_handle_reset,
|
.handle_reset = usb_host_handle_reset,
|
||||||
.handle_destroy = usb_host_handle_destroy,
|
.handle_destroy = usb_host_handle_destroy,
|
||||||
.usbdevice_name = "host",
|
.usbdevice_name = "host",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue