diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2012-03-01 04:51:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-02 19:35:39 -0500 |
commit | e553f182d55bd268fea3f106368e2344141c212a (patch) | |
tree | 0203a2d354d4f61001f4f2a89bdc39d3094c75a2 /drivers/staging/iio | |
parent | 4abf6f8b29e37f492078173a9d4cb808ce327ec0 (diff) |
staging: iio: core: Introduce debugfs support, add support for direct register access
Changes since V1:
Exclude iio debugfs code in case CONFIG_DEBUG_FS isn't enabled.
Introduce helper function iio_get_debugfs_dentry.
Document additions to struct iio_dev
iio_debugfs_read_reg:
Use snprintf.
Use a shorter fixed length.
Introduce len instead of pointer math.
iio_debugfs_write_reg:
Fix return value use PT_ERR.
Changes since V2:
Use debugfs_remove.
Fix whitespace damage.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/iio')
-rw-r--r-- | drivers/staging/iio/iio.h | 27 | ||||
-rw-r--r-- | drivers/staging/iio/industrialio-core.c | 137 |
2 files changed, 162 insertions, 2 deletions
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h index 6aa31e52c26..b9cd454f69e 100644 --- a/drivers/staging/iio/iio.h +++ b/drivers/staging/iio/iio.h | |||
@@ -286,6 +286,9 @@ struct iio_info { | |||
286 | struct iio_trigger *trig); | 286 | struct iio_trigger *trig); |
287 | int (*update_scan_mode)(struct iio_dev *indio_dev, | 287 | int (*update_scan_mode)(struct iio_dev *indio_dev, |
288 | const unsigned long *scan_mask); | 288 | const unsigned long *scan_mask); |
289 | int (*debugfs_reg_access)(struct iio_dev *indio_dev, | ||
290 | unsigned reg, unsigned writeval, | ||
291 | unsigned *readval); | ||
289 | }; | 292 | }; |
290 | 293 | ||
291 | /** | 294 | /** |
@@ -332,7 +335,9 @@ struct iio_buffer_setup_ops { | |||
332 | * @groups: [INTERN] attribute groups | 335 | * @groups: [INTERN] attribute groups |
333 | * @groupcounter: [INTERN] index of next attribute group | 336 | * @groupcounter: [INTERN] index of next attribute group |
334 | * @flags: [INTERN] file ops related flags including busy flag. | 337 | * @flags: [INTERN] file ops related flags including busy flag. |
335 | **/ | 338 | * @debugfs_dentry: [INTERN] device specific debugfs dentry. |
339 | * @cached_reg_addr: [INTERN] cached register address for debugfs reads. | ||
340 | */ | ||
336 | struct iio_dev { | 341 | struct iio_dev { |
337 | int id; | 342 | int id; |
338 | 343 | ||
@@ -366,6 +371,10 @@ struct iio_dev { | |||
366 | int groupcounter; | 371 | int groupcounter; |
367 | 372 | ||
368 | unsigned long flags; | 373 | unsigned long flags; |
374 | #if defined(CONFIG_DEBUG_FS) | ||
375 | struct dentry *debugfs_dentry; | ||
376 | unsigned cached_reg_addr; | ||
377 | #endif | ||
369 | }; | 378 | }; |
370 | 379 | ||
371 | /** | 380 | /** |
@@ -443,4 +452,20 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev) | |||
443 | & (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE); | 452 | & (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE); |
444 | }; | 453 | }; |
445 | 454 | ||
455 | /** | ||
456 | * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry | ||
457 | * @indio_dev: IIO device info structure for device | ||
458 | **/ | ||
459 | #if defined(CONFIG_DEBUG_FS) | ||
460 | static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) | ||
461 | { | ||
462 | return indio_dev->debugfs_dentry; | ||
463 | }; | ||
464 | #else | ||
465 | static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) | ||
466 | { | ||
467 | return NULL; | ||
468 | }; | ||
469 | #endif | ||
470 | |||
446 | #endif /* _INDUSTRIAL_IO_H_ */ | 471 | #endif /* _INDUSTRIAL_IO_H_ */ |
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index 0b8ba8f1483..868e3667200 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/cdev.h> | 22 | #include <linux/cdev.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/anon_inodes.h> | 24 | #include <linux/anon_inodes.h> |
25 | #include <linux/debugfs.h> | ||
25 | #include "iio.h" | 26 | #include "iio.h" |
26 | #include "iio_core.h" | 27 | #include "iio_core.h" |
27 | #include "iio_core_trigger.h" | 28 | #include "iio_core_trigger.h" |
@@ -39,6 +40,8 @@ struct bus_type iio_bus_type = { | |||
39 | }; | 40 | }; |
40 | EXPORT_SYMBOL(iio_bus_type); | 41 | EXPORT_SYMBOL(iio_bus_type); |
41 | 42 | ||
43 | static struct dentry *iio_debugfs_dentry; | ||
44 | |||
42 | static const char * const iio_data_type_name[] = { | 45 | static const char * const iio_data_type_name[] = { |
43 | [IIO_RAW] = "raw", | 46 | [IIO_RAW] = "raw", |
44 | [IIO_PROCESSED] = "input", | 47 | [IIO_PROCESSED] = "input", |
@@ -129,6 +132,8 @@ static int __init iio_init(void) | |||
129 | goto error_unregister_bus_type; | 132 | goto error_unregister_bus_type; |
130 | } | 133 | } |
131 | 134 | ||
135 | iio_debugfs_dentry = debugfs_create_dir("iio", NULL); | ||
136 | |||
132 | return 0; | 137 | return 0; |
133 | 138 | ||
134 | error_unregister_bus_type: | 139 | error_unregister_bus_type: |
@@ -142,6 +147,84 @@ static void __exit iio_exit(void) | |||
142 | if (iio_devt) | 147 | if (iio_devt) |
143 | unregister_chrdev_region(iio_devt, IIO_DEV_MAX); | 148 | unregister_chrdev_region(iio_devt, IIO_DEV_MAX); |
144 | bus_unregister(&iio_bus_type); | 149 | bus_unregister(&iio_bus_type); |
150 | debugfs_remove(iio_debugfs_dentry); | ||
151 | } | ||
152 | |||
153 | #if defined(CONFIG_DEBUG_FS) | ||
154 | static int iio_debugfs_open(struct inode *inode, struct file *file) | ||
155 | { | ||
156 | if (inode->i_private) | ||
157 | file->private_data = inode->i_private; | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf, | ||
163 | size_t count, loff_t *ppos) | ||
164 | { | ||
165 | struct iio_dev *indio_dev = file->private_data; | ||
166 | char buf[20]; | ||
167 | unsigned val = 0; | ||
168 | ssize_t len; | ||
169 | int ret; | ||
170 | |||
171 | ret = indio_dev->info->debugfs_reg_access(indio_dev, | ||
172 | indio_dev->cached_reg_addr, | ||
173 | 0, &val); | ||
174 | if (ret) | ||
175 | dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__); | ||
176 | |||
177 | len = snprintf(buf, sizeof(buf), "0x%X\n", val); | ||
178 | |||
179 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
180 | } | ||
181 | |||
182 | static ssize_t iio_debugfs_write_reg(struct file *file, | ||
183 | const char __user *userbuf, size_t count, loff_t *ppos) | ||
184 | { | ||
185 | struct iio_dev *indio_dev = file->private_data; | ||
186 | unsigned reg, val; | ||
187 | char buf[80]; | ||
188 | int ret; | ||
189 | |||
190 | count = min_t(size_t, count, (sizeof(buf)-1)); | ||
191 | if (copy_from_user(buf, userbuf, count)) | ||
192 | return -EFAULT; | ||
193 | |||
194 | buf[count] = 0; | ||
195 | |||
196 | ret = sscanf(buf, "%i %i", ®, &val); | ||
197 | |||
198 | switch (ret) { | ||
199 | case 1: | ||
200 | indio_dev->cached_reg_addr = reg; | ||
201 | break; | ||
202 | case 2: | ||
203 | indio_dev->cached_reg_addr = reg; | ||
204 | ret = indio_dev->info->debugfs_reg_access(indio_dev, reg, | ||
205 | val, NULL); | ||
206 | if (ret) { | ||
207 | dev_err(indio_dev->dev.parent, "%s: write failed\n", | ||
208 | __func__); | ||
209 | return ret; | ||
210 | } | ||
211 | break; | ||
212 | default: | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | return count; | ||
217 | } | ||
218 | |||
219 | static const struct file_operations iio_debugfs_reg_fops = { | ||
220 | .open = iio_debugfs_open, | ||
221 | .read = iio_debugfs_read_reg, | ||
222 | .write = iio_debugfs_write_reg, | ||
223 | }; | ||
224 | |||
225 | static void iio_device_unregister_debugfs(struct iio_dev *indio_dev) | ||
226 | { | ||
227 | debugfs_remove_recursive(indio_dev->debugfs_dentry); | ||
145 | } | 228 | } |
146 | 229 | ||
147 | static ssize_t iio_read_channel_ext_info(struct device *dev, | 230 | static ssize_t iio_read_channel_ext_info(struct device *dev, |
@@ -171,6 +254,49 @@ static ssize_t iio_write_channel_ext_info(struct device *dev, | |||
171 | return ext_info->write(indio_dev, this_attr->c, buf, len); | 254 | return ext_info->write(indio_dev, this_attr->c, buf, len); |
172 | } | 255 | } |
173 | 256 | ||
257 | static int iio_device_register_debugfs(struct iio_dev *indio_dev) | ||
258 | { | ||
259 | struct dentry *d; | ||
260 | |||
261 | if (indio_dev->info->debugfs_reg_access == NULL) | ||
262 | return 0; | ||
263 | |||
264 | if (IS_ERR(iio_debugfs_dentry)) | ||
265 | return 0; | ||
266 | |||
267 | indio_dev->debugfs_dentry = | ||
268 | debugfs_create_dir(dev_name(&indio_dev->dev), | ||
269 | iio_debugfs_dentry); | ||
270 | if (IS_ERR(indio_dev->debugfs_dentry)) | ||
271 | return PTR_ERR(indio_dev->debugfs_dentry); | ||
272 | |||
273 | if (indio_dev->debugfs_dentry == NULL) { | ||
274 | dev_warn(indio_dev->dev.parent, | ||
275 | "Failed to create debugfs directory\n"); | ||
276 | return -EFAULT; | ||
277 | } | ||
278 | |||
279 | d = debugfs_create_file("direct_reg_access", 0644, | ||
280 | indio_dev->debugfs_dentry, | ||
281 | indio_dev, &iio_debugfs_reg_fops); | ||
282 | if (!d) { | ||
283 | iio_device_unregister_debugfs(indio_dev); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | #else | ||
290 | static int iio_device_register_debugfs(struct iio_dev *indio_dev) | ||
291 | { | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void iio_device_unregister_debugfs(struct iio_dev *indio_dev) | ||
296 | { | ||
297 | } | ||
298 | #endif /* CONFIG_DEBUG_FS */ | ||
299 | |||
174 | static ssize_t iio_read_channel_info(struct device *dev, | 300 | static ssize_t iio_read_channel_info(struct device *dev, |
175 | struct device_attribute *attr, | 301 | struct device_attribute *attr, |
176 | char *buf) | 302 | char *buf) |
@@ -618,6 +744,7 @@ static void iio_dev_release(struct device *device) | |||
618 | iio_device_unregister_trigger_consumer(indio_dev); | 744 | iio_device_unregister_trigger_consumer(indio_dev); |
619 | iio_device_unregister_eventset(indio_dev); | 745 | iio_device_unregister_eventset(indio_dev); |
620 | iio_device_unregister_sysfs(indio_dev); | 746 | iio_device_unregister_sysfs(indio_dev); |
747 | iio_device_unregister_debugfs(indio_dev); | ||
621 | } | 748 | } |
622 | 749 | ||
623 | static struct device_type iio_dev_type = { | 750 | static struct device_type iio_dev_type = { |
@@ -734,11 +861,17 @@ int iio_device_register(struct iio_dev *indio_dev) | |||
734 | /* configure elements for the chrdev */ | 861 | /* configure elements for the chrdev */ |
735 | indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); | 862 | indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); |
736 | 863 | ||
864 | ret = iio_device_register_debugfs(indio_dev); | ||
865 | if (ret) { | ||
866 | dev_err(indio_dev->dev.parent, | ||
867 | "Failed to register debugfs interfaces\n"); | ||
868 | goto error_ret; | ||
869 | } | ||
737 | ret = iio_device_register_sysfs(indio_dev); | 870 | ret = iio_device_register_sysfs(indio_dev); |
738 | if (ret) { | 871 | if (ret) { |
739 | dev_err(indio_dev->dev.parent, | 872 | dev_err(indio_dev->dev.parent, |
740 | "Failed to register sysfs interfaces\n"); | 873 | "Failed to register sysfs interfaces\n"); |
741 | goto error_ret; | 874 | goto error_unreg_debugfs; |
742 | } | 875 | } |
743 | ret = iio_device_register_eventset(indio_dev); | 876 | ret = iio_device_register_eventset(indio_dev); |
744 | if (ret) { | 877 | if (ret) { |
@@ -765,6 +898,8 @@ error_unreg_eventset: | |||
765 | iio_device_unregister_eventset(indio_dev); | 898 | iio_device_unregister_eventset(indio_dev); |
766 | error_free_sysfs: | 899 | error_free_sysfs: |
767 | iio_device_unregister_sysfs(indio_dev); | 900 | iio_device_unregister_sysfs(indio_dev); |
901 | error_unreg_debugfs: | ||
902 | iio_device_unregister_debugfs(indio_dev); | ||
768 | error_ret: | 903 | error_ret: |
769 | return ret; | 904 | return ret; |
770 | } | 905 | } |