diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2017-06-06 16:08:49 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-09 11:52:08 +0200 |
commit | 125739cbc1c3b29c89ae44f85904cf18fc49a2fb (patch) | |
tree | 7abdd5759e483d01c2397e2fd81798d69955f9b3 | |
parent | 356d8009a5a4569f17a3508b50a347bdf4d5b337 (diff) | |
download | lwn-125739cbc1c3b29c89ae44f85904cf18fc49a2fb.tar.gz lwn-125739cbc1c3b29c89ae44f85904cf18fc49a2fb.zip |
drivers/fsi: Add sysfs files for FSI master & slave accesses
This change adds a 'raw' file for reads & writes, and a 'term' file for
the TERM command, and a 'break' file for issuing a BREAK.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/fsi/fsi-core.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index e9fbd9feeb3e..626cc0672552 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -287,6 +287,95 @@ static int fsi_slave_scan(struct fsi_slave *slave) return 0; } +static ssize_t fsi_slave_sysfs_raw_read(struct file *file, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj)); + size_t total_len, read_len; + int rc; + + if (off < 0) + return -EINVAL; + + if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff) + return -EINVAL; + + for (total_len = 0; total_len < count; total_len += read_len) { + read_len = min_t(size_t, count, 4); + read_len -= off & 0x3; + + rc = fsi_slave_read(slave, off, buf + total_len, read_len); + if (rc) + return rc; + + off += read_len; + } + + return count; +} + +static ssize_t fsi_slave_sysfs_raw_write(struct file *file, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj)); + size_t total_len, write_len; + int rc; + + if (off < 0) + return -EINVAL; + + if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff) + return -EINVAL; + + for (total_len = 0; total_len < count; total_len += write_len) { + write_len = min_t(size_t, count, 4); + write_len -= off & 0x3; + + rc = fsi_slave_write(slave, off, buf + total_len, write_len); + if (rc) + return rc; + + off += write_len; + } + + return count; +} + +static struct bin_attribute fsi_slave_raw_attr = { + .attr = { + .name = "raw", + .mode = 0600, + }, + .size = 0, + .read = fsi_slave_sysfs_raw_read, + .write = fsi_slave_sysfs_raw_write, +}; + +static ssize_t fsi_slave_sysfs_term_write(struct file *file, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj)); + struct fsi_master *master = slave->master; + + if (!master->term) + return -ENODEV; + + master->term(master, slave->link, slave->id); + return count; +} + +static struct bin_attribute fsi_slave_term_attr = { + .attr = { + .name = "term", + .mode = 0200, + }, + .size = 0, + .write = fsi_slave_sysfs_term_write, +}; + /* Encode slave local bus echo delay */ static inline uint32_t fsi_smode_echodly(int x) { @@ -402,6 +491,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id) return rc; } + rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr); + if (rc) + dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc); + + rc = device_create_bin_file(&slave->dev, &fsi_slave_term_attr); + if (rc) + dev_warn(&slave->dev, "failed to create term attr: %d\n", rc); + rc = fsi_slave_scan(slave); if (rc) dev_dbg(&master->dev, "failed during slave scan with: %d\n", @@ -523,6 +620,18 @@ static ssize_t master_rescan_store(struct device *dev, static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store); +static ssize_t master_break_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fsi_master *master = to_fsi_master(dev); + + fsi_master_break(master, 0); + + return count; +} + +static DEVICE_ATTR(break, 0200, NULL, master_break_store); + int fsi_master_register(struct fsi_master *master) { int rc; @@ -546,6 +655,13 @@ int fsi_master_register(struct fsi_master *master) return rc; } + rc = device_create_file(&master->dev, &dev_attr_break); + if (rc) { + device_unregister(&master->dev); + ida_simple_remove(&master_ida, master->idx); + return rc; + } + fsi_master_scan(master); return 0; |