static void gpio_update_port(struct usb_port *port) { struct gpio_port *gport = (struct gpio_port*) port; uint8_t gpio_val = 0; //We will just write to /sys/class/gpio/gpioX/value, so no need for the full //4096 (upper limit according to getconf) char file_path[64]; int32_t bytes_written = 0, fd = 0; gport->msg_mode = RESET; //Guard agains async reset requests. This guard is also needed for the //scenario where we are waiting to ping and device is reset. Then we will //still be in timeout list, but also reset. Since we then re-add port to //timeout (there is no USB timer), we create infinite loop and that is that if (gport->timeout_next.le_next != NULL || gport->timeout_next.le_prev != NULL) usb_monitor_lists_del_timeout((struct usb_port*) gport); //POWER_OFF is 0, so then we should switch on port if (!gport->pwr_state) gpio_val = 1; //Do a write, if write is successful then we update power state snprintf(file_path, sizeof(file_path), "/sys/class/gpio/gpio%u/value", gport->port_num); fd = open(file_path, O_WRONLY | FD_CLOEXEC); if (fd == -1) { USB_DEBUG_PRINT(port->ctx->logfile, "Failed to open gpio file\n"); usb_helpers_start_timeout((struct usb_port*) gport, DEFAULT_TIMEOUT_SEC); return; } if (gpio_val) bytes_written = write(fd, "1", 1); else bytes_written = write(fd, "0", 1); close(fd); if (bytes_written > 0) { gport->pwr_state = !gport->pwr_state; if (gport->pwr_state) { gport->msg_mode = IDLE; return; } } //There is no error case. If we fail, then we simply sleep and try again. No //device to free or anything //Sleep no matter if write is successful or not usb_helpers_start_timeout((struct usb_port*) gport, GPIO_TIMEOUT_SLEEP_SEC); //TODO: How to check if we are done? If we get here, and inverse of //power_state is off, then we have switched? Or? //USB_DEBUG_PRINT(stderr, "GPIO update\n"); }
/* libusb-callbacks for when devices are added/removed. It is also called * manually when we detect a hub, since we risk devices being added before we * see for example the YKUSH HID device */ static void usb_device_added(struct usb_monitor_ctx *ctx, libusb_device *dev) { //Check if device is connected to a port we control struct usb_port *port; struct libusb_device_descriptor desc; uint8_t path[USB_PATH_MAX]; uint8_t path_len; libusb_get_device_descriptor(dev, &desc); usb_helpers_fill_port_array(dev, path, &path_len); port = usb_monitor_lists_find_port_path(ctx, path, path_len); if (!port) return; //The enabled check is needed here sine we enable/disable async. So we can //process a disabled request before an add event. Of course, device will //most likely be remove in the next iteration of loop, but still ... if (port->msg_mode == RESET || !port->enabled) return; //Need to check port if it already has a device, since we can risk that we //are called two times for one device if (port->dev && port->dev == dev) return; USB_DEBUG_PRINT_SYSLOG(ctx, LOG_INFO, "Device: %.4x:%.4x added\n", desc.idVendor, desc.idProduct); //We need to configure port. So far, this is all generic port->vp.vid = desc.idVendor; port->vp.pid = desc.idProduct; port->status = PORT_DEV_CONNECTED; port->dev = dev; port->msg_mode = PING; libusb_ref_device(dev); usb_monitor_print_ports(ctx); //Whenever we detect a device, we need to add to timeout to send ping. //However, we need to wait longer than the initial five seconds to let //usb_modeswitch potentially works its magic usb_helpers_start_timeout(port, ADDED_TIMEOUT_SEC); }