struct mpsse_priv { struct gpio_chip gpio; struct usb_device *udev; /* USB device encompassing all MPSSEs */ struct usb_interface *intf; /* USB interface for this MPSSE */
u8 intf_id; /* USB interface number for this MPSSE */ struct work_struct irq_work; /* polling work thread */ struct mutex irq_mutex; /* lock over irq_data */
atomic_t irq_type[16]; /* pin -> edge detection type */
atomic_t irq_enabled; int id;
u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */
u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */
u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */
struct mutex io_mutex; /* sync I/O with disconnect */
};
struct bulk_desc { bool tx; /* direction of bulk transfer */
u8 *data; /* input (tx) or output (rx) */ int len; /* Length of `data` if tx, or length of */ /* Data to read if rx */ int len_actual; /* Length successfully transferred */ int timeout;
};
ret = mpsse_write(priv->intf, &buf, 1); if (ret) return ret;
ret = mpsse_read(priv->intf, &buf, 1); if (ret) return ret;
return buf;
}
staticint gpio_mpsse_set_multiple(struct gpio_chip *chip, unsignedlong *mask, unsignedlong *bits)
{ unsignedlong i, bank, bank_mask, bank_bits; int ret; struct mpsse_priv *priv = gpiochip_get_data(chip);
guard(mutex)(&priv->io_mutex);
for_each_set_clump8(i, bank_mask, mask, chip->ngpio) {
bank = i / 8;
if (bank_mask) {
bank_bits = bitmap_get_value8(bits, i); /* Zero out pins we want to change */
priv->gpio_outputs[bank] &= ~bank_mask; /* Set pins we care about */
priv->gpio_outputs[bank] |= bank_bits & bank_mask;
ret = gpio_mpsse_set_bank(priv, bank); if (ret) return ret;
}
}
return 0;
}
staticint gpio_mpsse_get_multiple(struct gpio_chip *chip, unsignedlong *mask, unsignedlong *bits)
{ unsignedlong i, bank, bank_mask; int ret; struct mpsse_priv *priv = gpiochip_get_data(chip);
guard(mutex)(&priv->io_mutex);
for_each_set_clump8(i, bank_mask, mask, chip->ngpio) {
bank = i / 8;
if (bank_mask) {
ret = gpio_mpsse_get_bank(priv, bank); if (ret < 0) return ret;
staticint gpio_mpsse_get_direction(struct gpio_chip *chip, unsignedint offset)
{ int ret; int bank = (offset & 8) >> 3; int bank_offset = offset & 7; struct mpsse_priv *priv = gpiochip_get_data(chip);
guard(mutex)(&priv->io_mutex); /* MPSSE directions are inverted */ if (priv->gpio_dir[bank] & BIT(bank_offset))
ret = GPIO_LINE_DIRECTION_OUT; else
ret = GPIO_LINE_DIRECTION_IN;
while ((irq_enabled = atomic_read(&priv->irq_enabled))) {
usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000); /* Cleanup will trigger at the end of the loop */
guard(mutex)(&priv->irq_mutex);
/* Check each value */ for (offset = 0; offset < priv->gpio.ngpio; ++offset) { if (old_value[offset] == -1) continue;
fire_irq = 0;
value = pin_states & BIT(offset);
switch (irq_type[offset]) { case IRQ_TYPE_EDGE_RISING:
fire_irq = value > old_value[offset]; break; case IRQ_TYPE_EDGE_FALLING:
fire_irq = value < old_value[offset]; break; case IRQ_TYPE_EDGE_BOTH:
fire_irq = value != old_value[offset]; break;
} if (!fire_irq) continue;
/* Sync back values so we can refer to them next tick */ for (offset = 0; offset < priv->gpio.ngpio; ++offset) if (irq_type[offset] != IRQ_TYPE_NONE &&
irq_enabled & BIT(offset))
old_value[offset] = pin_states & BIT(offset);
}
}
gpiochip_enable_irq(&priv->gpio, irqd->hwirq); /* If no-one else was using the IRQ, enable it */ if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) {
INIT_WORK(&priv->irq_work, gpio_mpsse_poll);
schedule_work(&priv->irq_work);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.