diff --git a/apps/vdpusb-proxy/main.c b/apps/vdpusb-proxy/main.c index 92fd5e0..33cbfdc 100644 --- a/apps/vdpusb-proxy/main.c +++ b/apps/vdpusb-proxy/main.c @@ -33,12 +33,14 @@ #include #include #include +#include struct proxy_device; static int done = 0; static struct vdp_usb_device* vdp_devs[5]; static struct proxy_device* proxy_devs[5]; +static int vdp_busnum = -1; struct proxy_device { @@ -48,10 +50,12 @@ struct proxy_device static void proxy_gadget_ep_enable(struct vdp_usb_gadget_ep* ep, int value) { + printf("ep enable\n"); } static void proxy_gadget_ep_enqueue(struct vdp_usb_gadget_ep* ep, struct vdp_usb_gadget_request* request) { + printf("ep enqueue\n"); request->status = vdp_usb_urb_status_completed; request->complete(request); request->destroy(request); @@ -59,6 +63,7 @@ static void proxy_gadget_ep_enqueue(struct vdp_usb_gadget_ep* ep, struct vdp_usb static void proxy_gadget_ep_dequeue(struct vdp_usb_gadget_ep* ep, struct vdp_usb_gadget_request* request) { + printf("ep dequeue\n"); request->status = vdp_usb_urb_status_unlinked; request->complete(request); request->destroy(request); @@ -66,43 +71,53 @@ static void proxy_gadget_ep_dequeue(struct vdp_usb_gadget_ep* ep, struct vdp_usb static vdp_usb_urb_status proxy_gadget_ep_clear_stall(struct vdp_usb_gadget_ep* ep) { + printf("ep clear stall\n"); return vdp_usb_urb_status_completed; } static void proxy_gadget_ep_destroy(struct vdp_usb_gadget_ep* ep) { + printf("ep destroy\n"); } static void proxy_gadget_interface_enable(struct vdp_usb_gadget_interface* interface, int value) { + printf("interface enable\n"); } static void proxy_gadget_interface_destroy(struct vdp_usb_gadget_interface* interface) { + printf("interface destroy\n"); } static void proxy_gadget_config_enable(struct vdp_usb_gadget_config* config, int value) { + printf("config enable\n"); } static void proxy_gadget_config_destroy(struct vdp_usb_gadget_config* config) { + printf("config destroy\n"); } static void proxy_gadget_reset(struct vdp_usb_gadget* gadget, int start) { + printf("gadget reset\n"); } static void proxy_gadget_power(struct vdp_usb_gadget* gadget, int on) { + printf("gadget power\n"); } static void proxy_gadget_set_address(struct vdp_usb_gadget* gadget, vdp_u32 address) { + printf("gadget set_address\n"); } static void proxy_gadget_destroy(struct vdp_usb_gadget* gadget) { + printf("gadget destroy\n"); } static struct vdp_usb_gadget_ep* create_proxy_gadget_ep(const struct libusb_endpoint_descriptor* desc, @@ -415,6 +430,10 @@ static int hotplug_callback_attach(libusb_context* ctx, libusb_device* dev, libu int i; vdp_usb_result vdp_res; + if (libusb_get_bus_number(dev) == vdp_busnum) { + return 0; + } + printf("device attached: %d:%d\n", libusb_get_bus_number(dev), libusb_get_port_number(dev)); @@ -453,6 +472,10 @@ static int hotplug_callback_detach(libusb_context* ctx, libusb_device* dev, libu { int i; + if (libusb_get_bus_number(dev) == vdp_busnum) { + return 0; + } + printf("device detached: %d:%d\n", libusb_get_bus_number(dev), libusb_get_port_number(dev)); @@ -519,6 +542,7 @@ int main(int argc, char* argv[]) res = 1; goto out3; } + vdp_busnum = vdp_usb_device_get_busnum(vdp_devs[i]); } if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { @@ -561,12 +585,126 @@ int main(int argc, char* argv[]) libusb_free_device_list(devs, 1); } - while (1) { - res = libusb_handle_events(NULL); - if (res != 0) { - printf("libusb_handle_events() failed: %s\n", libusb_error_name(res)); + while (!done) { + fd_set read_fds, write_fds; + const struct libusb_pollfd** libusb_fds; + struct timeval tv, zero_tv; + int have_tv, i, max_fd = 0; + int have_libusb_events = 0; + + zero_tv.tv_sec = 0; + zero_tv.tv_usec = 0; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + + libusb_fds = libusb_get_pollfds(NULL); + if (!libusb_fds) { + printf("libusb_get_pollfds() failed\n"); + break; + } + + have_tv = libusb_get_next_timeout(NULL, &tv); + if (have_tv < 0) { + printf("libusb_get_next_timeout() failed\n"); + libusb_free_pollfds(libusb_fds); + break; + } + + for (i = 0; i < sizeof(proxy_devs)/sizeof(proxy_devs[0]); ++i) { + vdp_fd fd = -1; + + if (!proxy_devs[i]) { + continue; + } + + vdp_usb_device_wait_event(vdp_devs[i], &fd); + + FD_SET(fd, &read_fds); + if (fd > max_fd) { + max_fd = fd; + } + } + + for (i = 0; libusb_fds[i]; ++i) { + if (libusb_fds[i]->events & POLLIN) { + FD_SET(libusb_fds[i]->fd, &read_fds); + if (libusb_fds[i]->fd > max_fd) { + max_fd = libusb_fds[i]->fd; + } + } else if (libusb_fds[i]->events & POLLOUT) { + FD_SET(libusb_fds[i]->fd, &write_fds); + if (libusb_fds[i]->fd > max_fd) { + max_fd = libusb_fds[i]->fd; + } + } + } + + assert(max_fd > 0); + + res = select(max_fd + 1, &read_fds, &write_fds, NULL, (have_tv ? &tv : NULL)); + + if (res < 0) { + printf("select error: %s\n", strerror(errno)); + libusb_free_pollfds(libusb_fds); + break; + } + + if (res == 0) { + have_libusb_events = 1; + } else { + for (i = 0; libusb_fds[i]; ++i) { + if (libusb_fds[i]->events & POLLIN) { + if (FD_ISSET(libusb_fds[i]->fd, &read_fds)) { + have_libusb_events = 1; + break; + } + } else if (libusb_fds[i]->events & POLLOUT) { + if (FD_ISSET(libusb_fds[i]->fd, &write_fds)) { + have_libusb_events = 1; + break; + } + } + } + } + + libusb_free_pollfds(libusb_fds); + + for (i = 0; i < sizeof(proxy_devs)/sizeof(proxy_devs[0]); ++i) { + vdp_fd fd = -1; + + if (!proxy_devs[i]) { + continue; + } + + vdp_usb_device_wait_event(vdp_devs[i], &fd); + + if (FD_ISSET(fd, &read_fds)) { + struct vdp_usb_event event; + + vdp_res = vdp_usb_device_get_event(vdp_devs[i], &event); + + if (vdp_res != vdp_usb_success) { + printf("failed to get event: %s\n", vdp_usb_result_to_str(vdp_res)); + i = 0; + break; + } + + vdp_usb_gadget_event(proxy_devs[i]->gadget, &event); + } + } + + if (i == 0) { break; } + + if (have_libusb_events) { + res = libusb_handle_events_timeout_completed(NULL, &zero_tv, NULL); + if (res != 0) { + printf("libusb_handle_events_timeout_completed() failed: %s\n", libusb_error_name(res)); + break; + } + } } for (i = 0; i < sizeof(proxy_devs)/sizeof(proxy_devs[0]); ++i) { diff --git a/include/vdp/usb.h b/include/vdp/usb.h index e2c1ecd..708abed 100644 --- a/include/vdp/usb.h +++ b/include/vdp/usb.h @@ -119,6 +119,9 @@ vdp_usb_result vdp_usb_device_attach(struct vdp_usb_device* device); */ vdp_usb_result vdp_usb_device_detach(struct vdp_usb_device* device); +int vdp_usb_device_get_busnum(struct vdp_usb_device* device); +int vdp_usb_device_get_portnum(struct vdp_usb_device* device); + /* * @} */ diff --git a/include/vdphci-common.h b/include/vdphci-common.h index dda3293..89817ad 100644 --- a/include/vdphci-common.h +++ b/include/vdphci-common.h @@ -27,6 +27,7 @@ #define _VDPHCI_COMMON_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -47,6 +48,22 @@ extern "C" { */ #define VDPHCI_DEVICE_PREFIX "vdphcidev" +/* + * Device control codes magic. + */ +#define VDPHCI_IOC_MAGIC 'V' + +/* + * Get info. + */ +struct vdphci_info +{ + int busnum; + int portnum; +}; + +#define VDPHCI_IOC_GET_INFO _IOR(VDPHCI_IOC_MAGIC, 0, struct vdphci_info) + /* * HEvent related. HEvents are sent by HCD to device. */ diff --git a/modules/vdphci/vdphci_device.c b/modules/vdphci/vdphci_device.c index 46b8c4d..4aac95a 100644 --- a/modules/vdphci/vdphci_device.c +++ b/modules/vdphci/vdphci_device.c @@ -873,6 +873,51 @@ static unsigned int vdphci_device_poll(struct file* file, struct poll_table_stru return ret; } +static long vdphci_device_ioctl(struct file* file, unsigned int cmd, unsigned long arg) +{ + struct vdphci_device* device = file->private_data; + int ret = 0; + union + { + struct vdphci_info info; + } value; + + if (_IOC_TYPE(cmd) != VDPHCI_IOC_MAGIC) { + return -ENOTTY; + } + + if (_IOC_DIR(cmd) & _IOC_READ) { + ret = !access_ok(VERIFY_WRITE, (void __user*)arg, _IOC_SIZE(cmd)); + } + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = ret || !access_ok(VERIFY_READ, (void __user*)arg, _IOC_SIZE(cmd)); + } + + if (ret != 0) { + return -EFAULT; + } + + ret = 0; + + switch (cmd) { + case VDPHCI_IOC_GET_INFO: + value.info.busnum = vdphci_hcd_to_usb_hcd(device->parent_hcd)->self.busnum; + value.info.portnum = device->port->number; + if (copy_to_user((struct vdphci_info __user*)arg, + &value.info, + sizeof(value.info)) != 0) { + ret = -EFAULT; + } + break; + default: + ret = -ENOTTY; + break; + } + + return ret; +} + static struct file_operations vdphci_device_ops = { .owner = THIS_MODULE, @@ -881,7 +926,8 @@ static struct file_operations vdphci_device_ops = .release = vdphci_device_release, .write = vdphci_device_write, .read = vdphci_device_read, - .poll = vdphci_device_poll + .poll = vdphci_device_poll, + .unlocked_ioctl = vdphci_device_ioctl }; int vdphci_device_init(struct vdphci_hcd* parent_hcd, struct vdphci_port* port, dev_t devno, struct vdphci_device* device) diff --git a/modules/vdphci/vdphci_hcd.c b/modules/vdphci/vdphci_hcd.c index d77d173..0a96dc3 100644 --- a/modules/vdphci/vdphci_hcd.c +++ b/modules/vdphci/vdphci_hcd.c @@ -818,6 +818,8 @@ int vdphci_hcd_add(struct device* controller, if (ret != 0) { usb_put_hcd(*hcd); *hcd = 0; + } else { + print_info("%s/%d added\n", (*hcd)->self.bus_name, (*hcd)->self.busnum); } return ret; @@ -825,6 +827,7 @@ int vdphci_hcd_add(struct device* controller, void vdphci_hcd_remove(struct usb_hcd* hcd) { + print_info("%s/%d removed\n", hcd->self.bus_name, hcd->self.busnum); usb_remove_hcd(hcd); usb_put_hcd(hcd); } diff --git a/vdpusb/vdp_usb_device.c b/vdpusb/vdp_usb_device.c index ba497a1..501ac1c 100644 --- a/vdpusb/vdp_usb_device.c +++ b/vdpusb/vdp_usb_device.c @@ -80,6 +80,7 @@ vdp_usb_result vdp_usb_device_open(struct vdp_usb_context* context, { char device_path[255]; int error; + struct vdphci_info info = { 0, 0 }; assert(context && device); if (!context || !device) { @@ -132,6 +133,19 @@ vdp_usb_result vdp_usb_device_open(struct vdp_usb_context* context, } } + if (ioctl((*device)->fd, VDPHCI_IOC_GET_INFO, &info) == -1) { + VDP_USB_LOG_ERROR(context, "device %d does not accept info ioctl", device_number); + + close((*device)->fd); + free(*device); + *device = NULL; + + return vdp_usb_protocol_error; + } + + (*device)->busnum = info.busnum; + (*device)->portnum = info.portnum; + VDP_USB_LOG_DEBUG(context, "device %d opened", device_number); return vdp_usb_success; @@ -220,6 +234,26 @@ vdp_usb_result vdp_usb_device_detach(struct vdp_usb_device* device) } } +int vdp_usb_device_get_busnum(struct vdp_usb_device* device) +{ + assert(device); + if (!device) { + return 0; + } + + return device->busnum; +} + +int vdp_usb_device_get_portnum(struct vdp_usb_device* device) +{ + assert(device); + if (!device) { + return 0; + } + + return device->portnum; +} + vdp_usb_result vdp_usb_device_wait_event(struct vdp_usb_device* device, vdp_fd* fd) { assert(device); diff --git a/vdpusb/vdp_usb_device.h b/vdpusb/vdp_usb_device.h index 8a5099b..c6c4fe7 100644 --- a/vdpusb/vdp_usb_device.h +++ b/vdpusb/vdp_usb_device.h @@ -37,6 +37,9 @@ struct vdp_usb_device vdp_u8 device_number; vdp_fd fd; + + int busnum; + int portnum; }; #endif