|
@@ -333,11 +333,49 @@ field##_show(struct device *dev, \
|
|
|
} \
|
|
|
static DEVICE_ATTR_RO(field);
|
|
|
|
|
|
+#define rpmsg_string_attr(field, member) \
|
|
|
+static ssize_t \
|
|
|
+field##_store(struct device *dev, struct device_attribute *attr, \
|
|
|
+ const char *buf, size_t sz) \
|
|
|
+{ \
|
|
|
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
|
|
|
+ char *new, *old; \
|
|
|
+ \
|
|
|
+ new = kstrndup(buf, sz, GFP_KERNEL); \
|
|
|
+ if (!new) \
|
|
|
+ return -ENOMEM; \
|
|
|
+ new[strcspn(new, "\n")] = '\0'; \
|
|
|
+ \
|
|
|
+ device_lock(dev); \
|
|
|
+ old = rpdev->member; \
|
|
|
+ if (strlen(new)) { \
|
|
|
+ rpdev->member = new; \
|
|
|
+ } else { \
|
|
|
+ kfree(new); \
|
|
|
+ rpdev->member = NULL; \
|
|
|
+ } \
|
|
|
+ device_unlock(dev); \
|
|
|
+ \
|
|
|
+ kfree(old); \
|
|
|
+ \
|
|
|
+ return sz; \
|
|
|
+} \
|
|
|
+static ssize_t \
|
|
|
+field##_show(struct device *dev, \
|
|
|
+ struct device_attribute *attr, char *buf) \
|
|
|
+{ \
|
|
|
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
|
|
|
+ \
|
|
|
+ return sprintf(buf, "%s\n", rpdev->member); \
|
|
|
+} \
|
|
|
+static DEVICE_ATTR_RW(field)
|
|
|
+
|
|
|
/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
|
|
|
rpmsg_show_attr(name, id.name, "%s\n");
|
|
|
rpmsg_show_attr(src, src, "0x%x\n");
|
|
|
rpmsg_show_attr(dst, dst, "0x%x\n");
|
|
|
rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
|
|
|
+rpmsg_string_attr(driver_override, driver_override);
|
|
|
|
|
|
static ssize_t modalias_show(struct device *dev,
|
|
|
struct device_attribute *attr, char *buf)
|
|
@@ -359,6 +397,7 @@ static struct attribute *rpmsg_dev_attrs[] = {
|
|
|
&dev_attr_dst.attr,
|
|
|
&dev_attr_src.attr,
|
|
|
&dev_attr_announce.attr,
|
|
|
+ &dev_attr_driver_override.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
ATTRIBUTE_GROUPS(rpmsg_dev);
|