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
39
hw/usb.c
39
hw/usb.c
@ -64,8 +64,9 @@ void usb_wakeup(USBDevice *dev)
|
||||
*/
|
||||
|
||||
#define SETUP_STATE_IDLE 0
|
||||
#define SETUP_STATE_DATA 1
|
||||
#define SETUP_STATE_ACK 2
|
||||
#define SETUP_STATE_SETUP 1
|
||||
#define SETUP_STATE_DATA 2
|
||||
#define SETUP_STATE_ACK 3
|
||||
|
||||
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) {
|
||||
ret = s->info->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;
|
||||
}
|
||||
if (ret < 0)
|
||||
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 */
|
||||
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_wakeup(USBDevice *dev);
|
||||
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);
|
||||
void usb_send_msg(USBDevice *dev, int msg);
|
||||
|
||||
|
263
usb-linux.c
263
usb-linux.c
@ -54,14 +54,6 @@ struct usb_ctrltransfer {
|
||||
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,
|
||||
int class_id, int vendor_id, int product_id,
|
||||
const char *product_name, int speed);
|
||||
@ -108,26 +100,6 @@ struct endp_data {
|
||||
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 {
|
||||
uint32_t bus_num;
|
||||
uint32_t addr;
|
||||
@ -146,7 +118,6 @@ typedef struct USBHostDevice {
|
||||
int closing;
|
||||
Notifier exit;
|
||||
|
||||
struct ctrl_struct ctrl;
|
||||
struct endp_data endp_table[MAX_ENDPOINTS];
|
||||
|
||||
/* Host side address */
|
||||
@ -269,26 +240,6 @@ static void async_free(AsyncURB *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)
|
||||
{
|
||||
USBHostDevice *s = opaque;
|
||||
@ -333,9 +284,6 @@ static void async_complete(void *opaque)
|
||||
switch (aurb->urb.status) {
|
||||
case 0:
|
||||
p->len = aurb->urb.actual_length;
|
||||
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
|
||||
async_complete_ctrl(s, p);
|
||||
}
|
||||
break;
|
||||
|
||||
case -EPIPE:
|
||||
@ -348,8 +296,12 @@ static void async_complete(void *opaque)
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -675,8 +627,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
|
||||
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;
|
||||
AsyncURB *aurb;
|
||||
int ret;
|
||||
@ -796,45 +749,39 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
|
||||
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;
|
||||
AsyncURB *aurb;
|
||||
int ret, value, index;
|
||||
int buffer_len;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Process certain standard device requests.
|
||||
* 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",
|
||||
s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
|
||||
s->ctrl.len);
|
||||
request >> 8, request & 0xff, value, index, length);
|
||||
|
||||
if (s->ctrl.req.bRequestType == 0) {
|
||||
switch (s->ctrl.req.bRequest) {
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
switch (request) {
|
||||
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->ctrl.req.bRequestType == 1 &&
|
||||
s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
|
||||
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
||||
return usb_host_set_interface(s, index, value);
|
||||
}
|
||||
|
||||
/* The rest are asynchronous */
|
||||
|
||||
buffer_len = 8 + s->ctrl.len;
|
||||
if (buffer_len > sizeof(s->ctrl.buffer)) {
|
||||
fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
|
||||
buffer_len, sizeof(s->ctrl.buffer));
|
||||
if (length > sizeof(dev->data_buf)) {
|
||||
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
|
||||
length, sizeof(dev->data_buf));
|
||||
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->endpoint = p->devep;
|
||||
|
||||
urb->buffer = &s->ctrl.req;
|
||||
urb->buffer_length = buffer_len;
|
||||
urb->buffer = &dev->setup_buf;
|
||||
urb->buffer_length = length + 8;
|
||||
|
||||
urb->usercontext = s;
|
||||
|
||||
@ -879,170 +826,6 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
|
||||
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)
|
||||
{
|
||||
uint8_t configuration;
|
||||
@ -1368,7 +1151,9 @@ static struct USBDeviceInfo usb_host_dev_info = {
|
||||
.qdev.name = "usb-host",
|
||||
.qdev.size = sizeof(USBHostDevice),
|
||||
.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_destroy = usb_host_handle_destroy,
|
||||
.usbdevice_name = "host",
|
||||
|
Loading…
Reference in New Issue
Block a user