diff options
author | Andy Shevchenko <andy.shevchenko@gmail.com> | 2010-09-10 10:10:50 +0300 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2010-10-23 21:11:13 +0800 |
commit | 130067ed15f6e8a1209898646878f5bc0a17d3dd (patch) | |
tree | 80108295840277210d1bdb8199d4ed60bd6b170e /drivers/mmc/card | |
parent | 3183aa1534de4e98ffb0527d4f2be7ac9f019a4e (diff) | |
download | linux-130067ed15f6e8a1209898646878f5bc0a17d3dd.tar.gz linux-130067ed15f6e8a1209898646878f5bc0a17d3dd.tar.bz2 linux-130067ed15f6e8a1209898646878f5bc0a17d3dd.zip |
mmc_test: move files from sysfs to debugfs
As proposed by Greg K-H it is more logical to keep files for the mmc_test
driver under debugfs.
Additionally this patch brings seq_file API for show() method. It allows
to write unlimited data to the file.
Example of usage:
# mount -t debugfs none /sys/kernel/debug
# modprobe mmc_test
[ 581.395843] mmc_test mmc0:0001: Card claimed for testing.
# echo 25 > /sys/kernel/debug/mmc0/mmc0\:0001/test
[ 604.568542] mmc0: Starting tests of card mmc0:0001...
[ 604.582733] mmc0: Test case 25. Best-case read performance into scattered pages...
[ 604.923553] mmc0: Transfer of 8192 sectors (4096 KiB) took 0.124664314 seconds (33644 kB/s, 32856 KiB/s)
[ 604.933227] mmc0: Result: OK
[ 604.936248] mmc0: Tests completed.
# cat /sys/kernel/debug/mmc0/mmc0\:0001/test
Test 25: 0
1 8192 0.124664314 33644784
Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Cc: Greg KH <greg@kroah.com>
Cc: Adrian Hunter <adrian.hunter@nokia.com>
Cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 142 |
1 files changed, 107 insertions, 35 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0c8b5685d4b7..6580af7b7cb8 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -19,6 +19,10 @@ #include <linux/swap.h> /* For nr_free_buffer_pages() */ #include <linux/list.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/seq_file.h> + #define RESULT_OK 0 #define RESULT_FAIL 1 #define RESULT_UNSUP_HOST 2 @@ -110,6 +114,18 @@ struct mmc_test_general_result { }; /** + * struct mmc_test_dbgfs_file - debugfs related file. + * @link: double-linked list + * @card: card under test + * @file: file created under debugfs + */ +struct mmc_test_dbgfs_file { + struct list_head link; + struct mmc_card *card; + struct dentry *file; +}; + +/** * struct mmc_test_card - test information. * @card: card under test * @scratch: transfer buffer @@ -2124,14 +2140,12 @@ static void mmc_test_free_result(struct mmc_card *card) mutex_unlock(&mmc_test_lock); } -static ssize_t mmc_test_show(struct device *dev, - struct device_attribute *attr, char *buf) +static LIST_HEAD(mmc_test_file_test); + +static int mtf_test_show(struct seq_file *sf, void *data) { - struct mmc_card *card = mmc_dev_to_card(dev); + struct mmc_card *card = (struct mmc_card *)sf->private; struct mmc_test_general_result *gr; - char *p = buf; - size_t len = PAGE_SIZE; - int ret; mutex_lock(&mmc_test_lock); @@ -2141,49 +2155,44 @@ static ssize_t mmc_test_show(struct device *dev, if (gr->card != card) continue; - ret = snprintf(p, len, "Test %d: %d\n", gr->testcase + 1, - gr->result); - if (ret < 0) - goto err; - if (ret >= len) { - ret = -ENOBUFS; - goto err; - } - p += ret; - len -= ret; + seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); list_for_each_entry(tr, &gr->tr_lst, link) { - ret = snprintf(p, len, "%u %d %lu.%09lu %u\n", + seq_printf(sf, "%u %d %lu.%09lu %u\n", tr->count, tr->sectors, (unsigned long)tr->ts.tv_sec, (unsigned long)tr->ts.tv_nsec, tr->rate); - if (ret < 0) - goto err; - if (ret >= len) { - ret = -ENOBUFS; - goto err; - } - p += ret; - len -= ret; } } - ret = PAGE_SIZE - len; -err: mutex_unlock(&mmc_test_lock); - return ret; + return 0; } -static ssize_t mmc_test_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static int mtf_test_open(struct inode *inode, struct file *file) { - struct mmc_card *card = mmc_dev_to_card(dev); + return single_open(file, mtf_test_show, inode->i_private); +} + +static ssize_t mtf_test_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct seq_file *sf = (struct seq_file *)file->private_data; + struct mmc_card *card = (struct mmc_card *)sf->private; struct mmc_test_card *test; + char lbuf[12]; long testcase; - if (strict_strtol(buf, 10, &testcase)) + if (count >= sizeof(lbuf)) + return -EINVAL; + + if (copy_from_user(lbuf, buf, count)) + return -EFAULT; + lbuf[count] = '\0'; + + if (strict_strtol(lbuf, 10, &testcase)) return -EINVAL; test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); @@ -2222,7 +2231,69 @@ static ssize_t mmc_test_store(struct device *dev, return count; } -static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store); +static const struct file_operations mmc_test_fops_test = { + .open = mtf_test_open, + .read = seq_read, + .write = mtf_test_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void mmc_test_free_file_test(struct mmc_card *card) +{ + struct mmc_test_dbgfs_file *df, *dfs; + + mutex_lock(&mmc_test_lock); + + list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) { + if (card && df->card != card) + continue; + debugfs_remove(df->file); + list_del(&df->link); + kfree(df); + } + + mutex_unlock(&mmc_test_lock); +} + +static int mmc_test_register_file_test(struct mmc_card *card) +{ + struct dentry *file = NULL; + struct mmc_test_dbgfs_file *df; + int ret = 0; + + mutex_lock(&mmc_test_lock); + + if (card->debugfs_root) + file = debugfs_create_file("test", S_IWUSR | S_IRUGO, + card->debugfs_root, card, &mmc_test_fops_test); + + if (IS_ERR_OR_NULL(file)) { + dev_err(&card->dev, + "Can't create file. Perhaps debugfs is disabled.\n"); + ret = -ENODEV; + goto err; + } + + df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL); + if (!df) { + debugfs_remove(file); + dev_err(&card->dev, + "Can't allocate memory for internal usage.\n"); + ret = -ENOMEM; + goto err; + } + + df->card = card; + df->file = file; + + list_add(&df->link, &mmc_test_file_test); + +err: + mutex_unlock(&mmc_test_lock); + + return ret; +} static int mmc_test_probe(struct mmc_card *card) { @@ -2231,7 +2302,7 @@ static int mmc_test_probe(struct mmc_card *card) if (!mmc_card_mmc(card) && !mmc_card_sd(card)) return -ENODEV; - ret = device_create_file(&card->dev, &dev_attr_test); + ret = mmc_test_register_file_test(card); if (ret) return ret; @@ -2243,7 +2314,7 @@ static int mmc_test_probe(struct mmc_card *card) static void mmc_test_remove(struct mmc_card *card) { mmc_test_free_result(card); - device_remove_file(&card->dev, &dev_attr_test); + mmc_test_free_file_test(card); } static struct mmc_driver mmc_driver = { @@ -2263,6 +2334,7 @@ static void __exit mmc_test_exit(void) { /* Clear stalled data if card is still plugged */ mmc_test_free_result(NULL); + mmc_test_free_file_test(NULL); mmc_unregister_driver(&mmc_driver); } |