Loading drivers/gpio/gpiolib-cdev.c +88 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/kfifo.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pinctrl/consumer.h> #include <linux/poll.h> #include <linux/spinlock.h> Loading Loading @@ -444,6 +445,8 @@ struct line { * @seqno: the sequence number for edge events generated on all lines in * this line request. Note that this is not used when @num_lines is 1, as * the line_seqno is then the same and is cheaper to calculate. * @config_mutex: mutex for serializing ioctl() calls to ensure consistency * of configuration, particularly multi-step accesses to desc flags. * @lines: the lines held by this line request, with @num_lines elements. */ struct linereq { Loading @@ -454,6 +457,7 @@ struct linereq { u32 event_buffer_size; DECLARE_KFIFO_PTR(events, struct gpio_v2_line_event); atomic_t seqno; struct mutex config_mutex; struct line lines[]; }; Loading Loading @@ -574,6 +578,8 @@ static void edge_detector_stop(struct line *line) free_irq(line->irq, line); line->irq = 0; } line->eflags = 0; } static int edge_detector_setup(struct line *line, Loading Loading @@ -615,6 +621,17 @@ static int edge_detector_setup(struct line *line, return 0; } static int edge_detector_update(struct line *line, u64 eflags, bool polarity_change) { if ((line->eflags == eflags) && !polarity_change) return 0; edge_detector_stop(line); return edge_detector_setup(line, eflags); } static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc, unsigned int line_idx) { Loading Loading @@ -799,6 +816,74 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) return 0; } static long linereq_set_config_unlocked(struct linereq *lr, struct gpio_v2_line_config *lc) { struct gpio_desc *desc; unsigned int i; u64 flags; bool polarity_change; int ret; for (i = 0; i < lr->num_lines; i++) { desc = lr->lines[i].desc; flags = gpio_v2_line_config_flags(lc, i); polarity_change = (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) != ((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0)); gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". */ if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { int val = gpio_v2_line_config_output_value(lc, i); edge_detector_stop(&lr->lines[i]); ret = gpiod_direction_output(desc, val); if (ret) return ret; } else if (flags & GPIO_V2_LINE_FLAG_INPUT) { ret = gpiod_direction_input(desc); if (ret) return ret; ret = edge_detector_update(&lr->lines[i], flags & GPIO_V2_LINE_EDGE_FLAGS, polarity_change); if (ret) return ret; } blocking_notifier_call_chain(&desc->gdev->notifier, GPIO_V2_LINE_CHANGED_CONFIG, desc); } return 0; } static long linereq_set_config(struct linereq *lr, void __user *ip) { struct gpio_v2_line_config lc; int ret; if (copy_from_user(&lc, ip, sizeof(lc))) return -EFAULT; ret = gpio_v2_line_config_validate(&lc, lr->num_lines); if (ret) return ret; mutex_lock(&lr->config_mutex); ret = linereq_set_config_unlocked(lr, &lc); mutex_unlock(&lr->config_mutex); return ret; } static long linereq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { Loading @@ -807,6 +892,8 @@ static long linereq_ioctl(struct file *file, unsigned int cmd, if (cmd == GPIO_V2_LINE_GET_VALUES_IOCTL) return linereq_get_values(lr, ip); else if (cmd == GPIO_V2_LINE_SET_CONFIG_IOCTL) return linereq_set_config(lr, ip); return -EINVAL; } Loading Loading @@ -968,6 +1055,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) } } mutex_init(&lr->config_mutex); init_waitqueue_head(&lr->wait); lr->event_buffer_size = ulr.event_buffer_size; if (lr->event_buffer_size == 0) Loading Loading
drivers/gpio/gpiolib-cdev.c +88 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/kfifo.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pinctrl/consumer.h> #include <linux/poll.h> #include <linux/spinlock.h> Loading Loading @@ -444,6 +445,8 @@ struct line { * @seqno: the sequence number for edge events generated on all lines in * this line request. Note that this is not used when @num_lines is 1, as * the line_seqno is then the same and is cheaper to calculate. * @config_mutex: mutex for serializing ioctl() calls to ensure consistency * of configuration, particularly multi-step accesses to desc flags. * @lines: the lines held by this line request, with @num_lines elements. */ struct linereq { Loading @@ -454,6 +457,7 @@ struct linereq { u32 event_buffer_size; DECLARE_KFIFO_PTR(events, struct gpio_v2_line_event); atomic_t seqno; struct mutex config_mutex; struct line lines[]; }; Loading Loading @@ -574,6 +578,8 @@ static void edge_detector_stop(struct line *line) free_irq(line->irq, line); line->irq = 0; } line->eflags = 0; } static int edge_detector_setup(struct line *line, Loading Loading @@ -615,6 +621,17 @@ static int edge_detector_setup(struct line *line, return 0; } static int edge_detector_update(struct line *line, u64 eflags, bool polarity_change) { if ((line->eflags == eflags) && !polarity_change) return 0; edge_detector_stop(line); return edge_detector_setup(line, eflags); } static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc, unsigned int line_idx) { Loading Loading @@ -799,6 +816,74 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) return 0; } static long linereq_set_config_unlocked(struct linereq *lr, struct gpio_v2_line_config *lc) { struct gpio_desc *desc; unsigned int i; u64 flags; bool polarity_change; int ret; for (i = 0; i < lr->num_lines; i++) { desc = lr->lines[i].desc; flags = gpio_v2_line_config_flags(lc, i); polarity_change = (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) != ((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0)); gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". */ if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { int val = gpio_v2_line_config_output_value(lc, i); edge_detector_stop(&lr->lines[i]); ret = gpiod_direction_output(desc, val); if (ret) return ret; } else if (flags & GPIO_V2_LINE_FLAG_INPUT) { ret = gpiod_direction_input(desc); if (ret) return ret; ret = edge_detector_update(&lr->lines[i], flags & GPIO_V2_LINE_EDGE_FLAGS, polarity_change); if (ret) return ret; } blocking_notifier_call_chain(&desc->gdev->notifier, GPIO_V2_LINE_CHANGED_CONFIG, desc); } return 0; } static long linereq_set_config(struct linereq *lr, void __user *ip) { struct gpio_v2_line_config lc; int ret; if (copy_from_user(&lc, ip, sizeof(lc))) return -EFAULT; ret = gpio_v2_line_config_validate(&lc, lr->num_lines); if (ret) return ret; mutex_lock(&lr->config_mutex); ret = linereq_set_config_unlocked(lr, &lc); mutex_unlock(&lr->config_mutex); return ret; } static long linereq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { Loading @@ -807,6 +892,8 @@ static long linereq_ioctl(struct file *file, unsigned int cmd, if (cmd == GPIO_V2_LINE_GET_VALUES_IOCTL) return linereq_get_values(lr, ip); else if (cmd == GPIO_V2_LINE_SET_CONFIG_IOCTL) return linereq_set_config(lr, ip); return -EINVAL; } Loading Loading @@ -968,6 +1055,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) } } mutex_init(&lr->config_mutex); init_waitqueue_head(&lr->wait); lr->event_buffer_size = ulr.event_buffer_size; if (lr->event_buffer_size == 0) Loading