Exemplo n.º 1
0
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);
}