summaryrefslogtreecommitdiff
path: root/compat/backport-4.5.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/backport-4.5.c')
-rw-r--r--compat/backport-4.5.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/compat/backport-4.5.c b/compat/backport-4.5.c
new file mode 100644
index 0000000..69751d5
--- /dev/null
+++ b/compat/backport-4.5.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright(c) 2015 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Backport functionality introduced in Linux 4.5.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/leds.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/leds.h>
+#include <linux/phy.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_IS_GEQ(3,19,0)
+int led_set_brightness_sync(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
+ return -EBUSY;
+
+ led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+ if (led_cdev->flags & LED_SUSPENDED)
+ return 0;
+
+ if (led_cdev->brightness_set_sync)
+ return led_cdev->brightness_set_sync(led_cdev,
+ led_cdev->brightness);
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(led_set_brightness_sync);
+#endif /* >= 3.19 */
+
+#if LINUX_VERSION_IS_GEQ(3,2,0)
+/**
+ * no_seek_end_llseek - llseek implementation for fixed-sized devices
+ * @file: file structure to seek on
+ * @offset: file offset to seek to
+ * @whence: type of seek
+ *
+ */
+loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
+{
+ switch (whence) {
+ case SEEK_SET: case SEEK_CUR:
+#if LINUX_VERSION_IS_GEQ(3,6,0)
+ return generic_file_llseek_size(file, offset, whence,
+ ~0ULL, 0);
+#else
+ return generic_file_llseek_size(file, offset, whence,
+ ~0ULL);
+#endif
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(no_seek_end_llseek);
+#endif /* >= 3.2 */
+
+/**
+ * memdup_user_nul - duplicate memory region from user space and NUL-terminate
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Returns an ERR_PTR() on failure.
+ */
+void *memdup_user_nul(const void __user *src, size_t len)
+{
+ char *p;
+
+ /*
+ * Always use GFP_KERNEL, since copy_from_user() can sleep and
+ * cause pagefault, which makes it pointless to use GFP_NOFS
+ * or GFP_ATOMIC.
+ */
+ p = kmalloc(len + 1, GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(p, src, len)) {
+ kfree(p);
+ return ERR_PTR(-EFAULT);
+ }
+ p[len] = '\0';
+
+ return p;
+}
+EXPORT_SYMBOL_GPL(memdup_user_nul);
+
+void phy_attached_info(struct phy_device *phydev)
+{
+ phy_attached_print(phydev, NULL);
+}
+EXPORT_SYMBOL_GPL(phy_attached_info);
+
+#define ATTACHED_FMT "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)"
+void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
+{
+ if (!fmt) {
+ dev_info(&phydev->dev, ATTACHED_FMT "\n",
+ phydev->drv->name, phydev_name(phydev),
+ phydev->irq);
+ } else {
+ va_list ap;
+
+ dev_info(&phydev->dev, ATTACHED_FMT,
+ phydev->drv->name, phydev_name(phydev),
+ phydev->irq);
+
+ va_start(ap, fmt);
+ vprintk(fmt, ap);
+ va_end(ap);
+ }
+}
+EXPORT_SYMBOL_GPL(phy_attached_print);
+
+static void devm_led_trigger_release(struct device *dev, void *res)
+{
+ led_trigger_unregister(*(struct led_trigger **)res);
+}
+
+int devm_led_trigger_register(struct device *dev,
+ struct led_trigger *trig)
+{
+ struct led_trigger **dr;
+ int rc;
+
+ dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
+ GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ *dr = trig;
+
+ rc = led_trigger_register(trig);
+ if (rc)
+ devres_free(dr);
+ else
+ devres_add(dev, dr);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(devm_led_trigger_register);