#endif
};
+DEFINE_FREE(linereq_free, struct linereq *, if (!IS_ERR_OR_NULL(_T)) linereq_free(_T))
+
static int linereq_create(struct gpio_device *gdev, void __user *ip)
{
struct gpio_v2_line_request ulr;
struct gpio_v2_line_config *lc;
- struct linereq *lr;
- struct file *file;
+ struct linereq *lr __free(linereq_free) = NULL;
u64 flags, edflags;
unsigned int i;
- int fd, ret;
+ int ret;
if (copy_from_user(&ulr, ip, sizeof(ulr)))
return -EFAULT;
/* label is only initialized if consumer is set */
lr->label = kstrndup(ulr.consumer, sizeof(ulr.consumer) - 1,
GFP_KERNEL);
- if (!lr->label) {
- ret = -ENOMEM;
- goto out_free_linereq;
- }
+ if (!lr->label)
+ return -ENOMEM;
}
mutex_init(&lr->config_mutex);
u32 offset = ulr.offsets[i];
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
- if (IS_ERR(desc)) {
- ret = PTR_ERR(desc);
- goto out_free_linereq;
- }
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
ret = gpiod_request_user(desc, lr->label);
if (ret)
- goto out_free_linereq;
+ return ret;
lr->lines[i].desc = desc;
flags = gpio_v2_line_config_flags(lc, i);
ret = gpiod_set_transitory(desc, false);
if (ret < 0)
- goto out_free_linereq;
+ return ret;
edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/*
ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
- goto out_free_linereq;
+ return ret;
} else if (flags & GPIO_V2_LINE_FLAG_INPUT) {
ret = gpiod_direction_input_nonotify(desc);
if (ret)
- goto out_free_linereq;
+ return ret;
ret = edge_detector_setup(&lr->lines[i], lc, i,
edflags);
if (ret)
- goto out_free_linereq;
+ return ret;
}
lr->lines[i].edflags = edflags;
ret = blocking_notifier_chain_register(&gdev->device_notifier,
&lr->device_unregistered_nb);
if (ret)
- goto out_free_linereq;
-
- fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- ret = fd;
- goto out_free_linereq;
- }
+ return ret;
- file = anon_inode_getfile("gpio-line", &line_fileops, lr,
- O_RDONLY | O_CLOEXEC);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
- goto out_put_unused_fd;
- }
+ FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
+ anon_inode_getfile("gpio-line", &line_fileops, lr,
+ O_RDONLY | O_CLOEXEC));
+ if (fdf.err)
+ return fdf.err;
+ retain_and_null_ptr(lr);
- ulr.fd = fd;
- if (copy_to_user(ip, &ulr, sizeof(ulr))) {
- /*
- * fput() will trigger the release() callback, so do not go onto
- * the regular error cleanup path here.
- */
- fput(file);
- put_unused_fd(fd);
+ ulr.fd = fd_prepare_fd(fdf);
+ if (copy_to_user(ip, &ulr, sizeof(ulr)))
return -EFAULT;
- }
- fd_install(fd, file);
+ fd_publish(fdf);
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
- lr->num_lines);
+ ulr.num_lines);
return 0;
-
-out_put_unused_fd:
- put_unused_fd(fd);
-out_free_linereq:
- linereq_free(lr);
- return ret;
}
#ifdef CONFIG_GPIO_CDEV_V1
return IRQ_WAKE_THREAD;
}
+DEFINE_FREE(lineevent_free, struct lineevent_state *, if (!IS_ERR_OR_NULL(_T)) lineevent_free(_T))
+
static int lineevent_create(struct gpio_device *gdev, void __user *ip)
{
struct gpioevent_request eventreq;
- struct lineevent_state *le;
+ struct lineevent_state *le __free(lineevent_free) = NULL;
struct gpio_desc *desc;
- struct file *file;
u32 offset;
u32 lflags;
u32 eflags;
- int fd;
int ret;
int irq, irqflags = 0;
char *label;
le->label = kstrndup(eventreq.consumer_label,
sizeof(eventreq.consumer_label) - 1,
GFP_KERNEL);
- if (!le->label) {
- ret = -ENOMEM;
- goto out_free_le;
- }
+ if (!le->label)
+ return -ENOMEM;
}
ret = gpiod_request_user(desc, le->label);
if (ret)
- goto out_free_le;
+ return ret;
le->desc = desc;
le->eflags = eflags;
ret = gpiod_direction_input(desc);
if (ret)
- goto out_free_le;
+ return ret;
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
irq = gpiod_to_irq(desc);
- if (irq <= 0) {
- ret = -ENODEV;
- goto out_free_le;
- }
+ if (irq <= 0)
+ return -ENODEV;
if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
irqflags |= test_bit(GPIOD_FLAG_ACTIVE_LOW, &desc->flags) ?
ret = blocking_notifier_chain_register(&gdev->device_notifier,
&le->device_unregistered_nb);
if (ret)
- goto out_free_le;
+ return ret;
label = make_irq_label(le->label);
- if (IS_ERR(label)) {
- ret = PTR_ERR(label);
- goto out_free_le;
- }
+ if (IS_ERR(label))
+ return PTR_ERR(label);
/* Request a thread to read the events */
ret = request_threaded_irq(irq,
le);
if (ret) {
free_irq_label(label);
- goto out_free_le;
+ return ret;
}
le->irq = irq;
- fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- ret = fd;
- goto out_free_le;
- }
-
- file = anon_inode_getfile("gpio-event",
- &lineevent_fileops,
- le,
- O_RDONLY | O_CLOEXEC);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
- goto out_put_unused_fd;
- }
+ FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
+ anon_inode_getfile("gpio-event", &lineevent_fileops, le,
+ O_RDONLY | O_CLOEXEC));
+ if (fdf.err)
+ return fdf.err;
+ retain_and_null_ptr(le);
- eventreq.fd = fd;
- if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
- /*
- * fput() will trigger the release() callback, so do not go onto
- * the regular error cleanup path here.
- */
- fput(file);
- put_unused_fd(fd);
+ eventreq.fd = fd_prepare_fd(fdf);
+ if (copy_to_user(ip, &eventreq, sizeof(eventreq)))
return -EFAULT;
- }
- fd_install(fd, file);
+ fd_publish(fdf);
return 0;
-
-out_put_unused_fd:
- put_unused_fd(fd);
-out_free_le:
- lineevent_free(le);
- return ret;
}
static void gpio_v2_line_info_to_v1(struct gpio_v2_line_info *info_v2,