diff options
-rw-r--r-- | hw/usb-bus.c | 1 | ||||
-rw-r--r-- | hw/usb.c | 30 | ||||
-rw-r--r-- | hw/usb.h | 14 | ||||
-rw-r--r-- | usb-linux.c | 63 |
4 files changed, 74 insertions, 34 deletions
diff --git a/hw/usb-bus.c b/hw/usb-bus.c index bd4afa7e2b..016a3f2bb4 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -75,6 +75,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) dev->info = info; dev->auto_attach = 1; QLIST_INIT(&dev->strings); + usb_ep_init(dev); rc = usb_claim_port(dev); if (rc != 0) { return rc; @@ -414,3 +414,33 @@ void usb_packet_cleanup(USBPacket *p) { qemu_iovec_destroy(&p->iov); } + +void usb_ep_init(USBDevice *dev) +{ + int ep; + + for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { + dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID; + dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID; + } +} + +struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out; + assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT); + assert(ep > 0 && ep <= USB_MAX_ENDPOINTS); + return eps + ep - 1; +} + +uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + return uep->type; +} + +void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + uep->type = type; +} @@ -144,6 +144,7 @@ #define USB_ENDPOINT_XFER_ISOC 1 #define USB_ENDPOINT_XFER_BULK 2 #define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_XFER_INVALID 255 typedef struct USBBus USBBus; typedef struct USBBusOps USBBusOps; @@ -151,6 +152,7 @@ typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; typedef struct USBDeviceInfo USBDeviceInfo; typedef struct USBPacket USBPacket; +typedef struct USBEndpoint USBEndpoint; typedef struct USBDesc USBDesc; typedef struct USBDescID USBDescID; @@ -171,6 +173,10 @@ struct USBDescString { #define USB_MAX_ENDPOINTS 15 #define USB_MAX_INTERFACES 16 +struct USBEndpoint { + uint8_t type; +}; + /* definition of a USB device */ struct USBDevice { DeviceState qdev; @@ -196,6 +202,9 @@ struct USBDevice { int32_t setup_len; int32_t setup_index; + USBEndpoint ep_in[USB_MAX_ENDPOINTS]; + USBEndpoint ep_out[USB_MAX_ENDPOINTS]; + QLIST_HEAD(, USBDescString) strings; const USBDescDevice *device; @@ -322,6 +331,11 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); +void usb_ep_init(USBDevice *dev); +struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep); +uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep); +void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type); + void usb_attach(USBPort *port); void usb_detach(USBPort *port); void usb_reset(USBPort *port); diff --git a/usb-linux.c b/usb-linux.c index ded0726dad..9967975f2b 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -67,12 +67,10 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port, #endif #define PRODUCT_NAME_SZ 32 -#define MAX_ENDPOINTS 15 #define MAX_PORTLEN 16 /* endpoint association data */ #define ISO_FRAME_DESC_PER_URB 32 -#define INVALID_EP_TYPE 255 /* devio.c limits single requests to 16k */ #define MAX_USBFS_BUFFER_SIZE 16384 @@ -80,7 +78,6 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port, typedef struct AsyncURB AsyncURB; struct endp_data { - uint8_t type; uint8_t halted; uint8_t iso_started; AsyncURB *iso_urb; @@ -110,8 +107,8 @@ typedef struct USBHostDevice { uint32_t iso_urb_count; Notifier exit; - struct endp_data ep_in[MAX_ENDPOINTS]; - struct endp_data ep_out[MAX_ENDPOINTS]; + struct endp_data ep_in[USB_MAX_ENDPOINTS]; + struct endp_data ep_out[USB_MAX_ENDPOINTS]; QLIST_HEAD(, AsyncURB) aurbs; /* Host side address */ @@ -133,6 +130,19 @@ static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); static int usb_linux_update_endp_table(USBHostDevice *s); +static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) +{ + static const int usbfs[] = { + [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL, + [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO, + [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK, + [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT, + }; + uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep); + assert(type < ARRAY_SIZE(usbfs)); + return usbfs[type]; +} + static int usb_host_do_reset(USBHostDevice *dev) { struct timeval s, e; @@ -156,18 +166,18 @@ static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep) { struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out; assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT); - assert(ep > 0 && ep <= MAX_ENDPOINTS); + assert(ep > 0 && ep <= USB_MAX_ENDPOINTS); return eps + ep - 1; } static int is_isoc(USBHostDevice *s, int pid, int ep) { - return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO; + return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC; } static int is_valid(USBHostDevice *s, int pid, int ep) { - return get_endp(s, pid, ep)->type != INVALID_EP_TYPE; + return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID; } static int is_halted(USBHostDevice *s, int pid, int ep) @@ -896,7 +906,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) urb = &aurb->urb; urb->endpoint = ep; - urb->type = USBDEVFS_URB_TYPE_BULK; + urb->type = usb_host_usbfs_type(s, p); urb->usercontext = s; urb->buffer = pbuf; urb->buffer_length = prem; @@ -992,7 +1002,7 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt); - for (i = 1; i <= MAX_ENDPOINTS; i++) { + for (i = 1; i <= USB_MAX_ENDPOINTS; i++) { if (is_isoc(s, USB_TOKEN_IN, i)) { usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i); } @@ -1126,10 +1136,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) int interface, length, i, ep, pid; struct endp_data *epd; - for (i = 0; i < MAX_ENDPOINTS; i++) { - s->ep_in[i].type = INVALID_EP_TYPE; - s->ep_out[i].type = INVALID_EP_TYPE; - } + usb_ep_init(&s->dev); if (s->dev.configuration == 0) { /* not configured yet -- leave all endpoints disabled */ @@ -1192,27 +1199,15 @@ static int usb_linux_update_endp_table(USBHostDevice *s) return 1; } - switch (descriptors[i + 3] & 0x3) { - case 0x00: - type = USBDEVFS_URB_TYPE_CONTROL; - break; - case 0x01: - type = USBDEVFS_URB_TYPE_ISO; + type = descriptors[i + 3] & 0x3; + if (type == USB_ENDPOINT_XFER_ISOC) { set_max_packet_size(s, pid, ep, descriptors + i); - break; - case 0x02: - type = USBDEVFS_URB_TYPE_BULK; - break; - case 0x03: - type = USBDEVFS_URB_TYPE_INTERRUPT; - break; - default: - DPRINTF("usb_host: malformed endpoint type\n"); - type = USBDEVFS_URB_TYPE_BULK; - } + }; + assert(usb_ep_get_type(&s->dev, pid, ep) == + USB_ENDPOINT_XFER_INVALID); + usb_ep_set_type(&s->dev, pid, ep, type); + epd = get_endp(s, pid, ep); - assert(epd->type == INVALID_EP_TYPE); - epd->type = type; epd->halted = 0; i += descriptors[i]; @@ -1371,7 +1366,7 @@ static int usb_host_close(USBHostDevice *dev) qemu_set_fd_handler(dev->fd, NULL, NULL, NULL); dev->closing = 1; - for (i = 1; i <= MAX_ENDPOINTS; i++) { + for (i = 1; i <= USB_MAX_ENDPOINTS; i++) { if (is_isoc(dev, USB_TOKEN_IN, i)) { usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i); } |