|
@@ -21,6 +21,7 @@
|
|
#include <linux/uaccess.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/anon_inodes.h>
|
|
#include <linux/anon_inodes.h>
|
|
|
|
+#include <linux/file.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/timekeeping.h>
|
|
#include <linux/timekeeping.h>
|
|
@@ -423,6 +424,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
|
{
|
|
{
|
|
struct gpiohandle_request handlereq;
|
|
struct gpiohandle_request handlereq;
|
|
struct linehandle_state *lh;
|
|
struct linehandle_state *lh;
|
|
|
|
+ struct file *file;
|
|
int fd, i, ret;
|
|
int fd, i, ret;
|
|
|
|
|
|
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
|
|
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
|
|
@@ -499,26 +501,41 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
|
i--;
|
|
i--;
|
|
lh->numdescs = handlereq.lines;
|
|
lh->numdescs = handlereq.lines;
|
|
|
|
|
|
- fd = anon_inode_getfd("gpio-linehandle",
|
|
|
|
- &linehandle_fileops,
|
|
|
|
- lh,
|
|
|
|
- O_RDONLY | O_CLOEXEC);
|
|
|
|
|
|
+ fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
|
if (fd < 0) {
|
|
if (fd < 0) {
|
|
ret = fd;
|
|
ret = fd;
|
|
goto out_free_descs;
|
|
goto out_free_descs;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ file = anon_inode_getfile("gpio-linehandle",
|
|
|
|
+ &linehandle_fileops,
|
|
|
|
+ lh,
|
|
|
|
+ O_RDONLY | O_CLOEXEC);
|
|
|
|
+ if (IS_ERR(file)) {
|
|
|
|
+ ret = PTR_ERR(file);
|
|
|
|
+ goto out_put_unused_fd;
|
|
|
|
+ }
|
|
|
|
+
|
|
handlereq.fd = fd;
|
|
handlereq.fd = fd;
|
|
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
|
|
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
|
|
- ret = -EFAULT;
|
|
|
|
- goto out_free_descs;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * fput() will trigger the release() callback, so do not go onto
|
|
|
|
+ * the regular error cleanup path here.
|
|
|
|
+ */
|
|
|
|
+ fput(file);
|
|
|
|
+ put_unused_fd(fd);
|
|
|
|
+ return -EFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fd_install(fd, file);
|
|
|
|
+
|
|
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
|
|
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
|
|
lh->numdescs);
|
|
lh->numdescs);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+out_put_unused_fd:
|
|
|
|
+ put_unused_fd(fd);
|
|
out_free_descs:
|
|
out_free_descs:
|
|
for (; i >= 0; i--)
|
|
for (; i >= 0; i--)
|
|
gpiod_free(lh->descs[i]);
|
|
gpiod_free(lh->descs[i]);
|
|
@@ -721,6 +738,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
|
struct gpioevent_request eventreq;
|
|
struct gpioevent_request eventreq;
|
|
struct lineevent_state *le;
|
|
struct lineevent_state *le;
|
|
struct gpio_desc *desc;
|
|
struct gpio_desc *desc;
|
|
|
|
+ struct file *file;
|
|
u32 offset;
|
|
u32 offset;
|
|
u32 lflags;
|
|
u32 lflags;
|
|
u32 eflags;
|
|
u32 eflags;
|
|
@@ -815,23 +833,38 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
|
if (ret)
|
|
if (ret)
|
|
goto out_free_desc;
|
|
goto out_free_desc;
|
|
|
|
|
|
- fd = anon_inode_getfd("gpio-event",
|
|
|
|
- &lineevent_fileops,
|
|
|
|
- le,
|
|
|
|
- O_RDONLY | O_CLOEXEC);
|
|
|
|
|
|
+ fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
|
if (fd < 0) {
|
|
if (fd < 0) {
|
|
ret = fd;
|
|
ret = fd;
|
|
goto out_free_irq;
|
|
goto out_free_irq;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+
|
|
eventreq.fd = fd;
|
|
eventreq.fd = fd;
|
|
if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
|
|
if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
|
|
- ret = -EFAULT;
|
|
|
|
- goto out_free_irq;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * fput() will trigger the release() callback, so do not go onto
|
|
|
|
+ * the regular error cleanup path here.
|
|
|
|
+ */
|
|
|
|
+ fput(file);
|
|
|
|
+ put_unused_fd(fd);
|
|
|
|
+ return -EFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fd_install(fd, file);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+out_put_unused_fd:
|
|
|
|
+ put_unused_fd(fd);
|
|
out_free_irq:
|
|
out_free_irq:
|
|
free_irq(le->irq, le);
|
|
free_irq(le->irq, le);
|
|
out_free_desc:
|
|
out_free_desc:
|