208 lines
4.3 KiB
C
208 lines
4.3 KiB
C
|
/*
|
||
|
* Copyright (c) 2011, The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
* only version 2 as published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*/
|
||
|
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/crc-ccitt.h>
|
||
|
#include <mach/diag_bridge.h>
|
||
|
|
||
|
#define DRIVER_DESC "USB host diag bridge driver test"
|
||
|
#define DRIVER_VERSION "1.0"
|
||
|
|
||
|
#define RD_BUF_SIZE 2048
|
||
|
#define DIAG_TEST_CONNECTED 0
|
||
|
|
||
|
struct diag_test_dev {
|
||
|
char *read_buf;
|
||
|
struct work_struct read_w;
|
||
|
unsigned long flags;
|
||
|
|
||
|
struct diag_bridge_ops ops;
|
||
|
};
|
||
|
static struct diag_test_dev *__dev;
|
||
|
static struct dentry *dent;
|
||
|
|
||
|
static void
|
||
|
diag_test_read_complete_cb(void *d, char *buf, size_t size, size_t actual)
|
||
|
{
|
||
|
if (actual < 0) {
|
||
|
pr_err("%s: read complete err\n", __func__);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
print_hex_dump(KERN_INFO, "to_host:", 0, 1, 1, buf, actual, false);
|
||
|
}
|
||
|
static void diag_test_read_work(struct work_struct *w)
|
||
|
{
|
||
|
struct diag_test_dev *dev =
|
||
|
container_of(w, struct diag_test_dev, read_w);
|
||
|
|
||
|
memset(dev->read_buf, 0, RD_BUF_SIZE);
|
||
|
diag_bridge_read(dev->read_buf, RD_BUF_SIZE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
diag_test_write_complete_cb(void *d, char *buf, size_t size, size_t actual)
|
||
|
{
|
||
|
struct diag_test_dev *dev = d;
|
||
|
|
||
|
if (actual > 0)
|
||
|
schedule_work(&dev->read_w);
|
||
|
}
|
||
|
|
||
|
#if defined(CONFIG_DEBUG_FS)
|
||
|
#define DEBUG_BUF_SIZE 1024
|
||
|
static ssize_t send_ping_cmd(struct file *file, const char __user *ubuf,
|
||
|
size_t count, loff_t *ppos)
|
||
|
{
|
||
|
struct diag_test_dev *dev = __dev;
|
||
|
unsigned char *buf;
|
||
|
int temp = sizeof(unsigned char) * 4;
|
||
|
|
||
|
if (!dev)
|
||
|
return -ENODEV;
|
||
|
|
||
|
buf = kmalloc(temp, GFP_KERNEL);
|
||
|
if (!buf) {
|
||
|
pr_err("%s: unable to allocate mem for ping cmd\n",
|
||
|
__func__);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
/* hdlc encoded ping command */
|
||
|
buf[0] = 0x0C;
|
||
|
buf[1] = 0x14;
|
||
|
buf[2] = 0x3A;
|
||
|
buf[3] = 0x7E;
|
||
|
|
||
|
diag_bridge_write(buf, temp);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
const struct file_operations diag_test_ping_ops = {
|
||
|
.write = send_ping_cmd,
|
||
|
};
|
||
|
|
||
|
static void diag_test_debug_init(void)
|
||
|
{
|
||
|
struct dentry *dfile;
|
||
|
|
||
|
dent = debugfs_create_dir("diag_test", 0);
|
||
|
if (IS_ERR(dent))
|
||
|
return;
|
||
|
|
||
|
dfile = debugfs_create_file("send_ping", 0444, dent,
|
||
|
0, &diag_test_ping_ops);
|
||
|
if (!dfile || IS_ERR(dfile))
|
||
|
debugfs_remove(dent);
|
||
|
}
|
||
|
#else
|
||
|
static void diag_test_debug_init(void) { }
|
||
|
#endif
|
||
|
|
||
|
static int diag_test_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
diag_bridge_close();
|
||
|
|
||
|
if (dent) {
|
||
|
debugfs_remove_recursive(dent);
|
||
|
dent = NULL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int diag_test_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
struct diag_test_dev *dev = __dev;
|
||
|
int ret = 0;
|
||
|
|
||
|
pr_info("%s:\n", __func__);
|
||
|
|
||
|
ret = diag_bridge_open(&dev->ops);
|
||
|
if (ret)
|
||
|
pr_err("diag open failed: %d", ret);
|
||
|
|
||
|
|
||
|
diag_test_debug_init();
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static struct platform_driver diag_test = {
|
||
|
.remove = diag_test_remove,
|
||
|
.probe = diag_test_probe,
|
||
|
.driver = {
|
||
|
.name = "diag_bridge",
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static int __init diag_test_init(void)
|
||
|
{
|
||
|
struct diag_test_dev *dev;
|
||
|
int ret = 0;
|
||
|
|
||
|
pr_info("%s\n", __func__);
|
||
|
|
||
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||
|
if (!dev)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
__dev = dev;
|
||
|
|
||
|
dev->ops.read_complete_cb = diag_test_read_complete_cb;
|
||
|
dev->ops.write_complete_cb = diag_test_write_complete_cb;
|
||
|
dev->read_buf = kmalloc(RD_BUF_SIZE, GFP_KERNEL);
|
||
|
if (!dev->read_buf) {
|
||
|
pr_err("%s: unable to allocate read buffer\n", __func__);
|
||
|
kfree(dev);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
dev->ops.ctxt = dev;
|
||
|
INIT_WORK(&dev->read_w, diag_test_read_work);
|
||
|
|
||
|
ret = platform_driver_register(&diag_test);
|
||
|
if (ret)
|
||
|
pr_err("%s: platform driver %s register failed %d\n",
|
||
|
__func__, diag_test.driver.name, ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void __exit diag_test_exit(void)
|
||
|
{
|
||
|
struct diag_test_dev *dev = __dev;
|
||
|
|
||
|
pr_info("%s:\n", __func__);
|
||
|
|
||
|
if (test_bit(DIAG_TEST_CONNECTED, &dev->flags))
|
||
|
diag_bridge_close();
|
||
|
|
||
|
kfree(dev->read_buf);
|
||
|
kfree(dev);
|
||
|
|
||
|
}
|
||
|
|
||
|
module_init(diag_test_init);
|
||
|
module_exit(diag_test_exit);
|
||
|
|
||
|
MODULE_DESCRIPTION(DRIVER_DESC);
|
||
|
MODULE_VERSION(DRIVER_VERSION);
|
||
|
MODULE_LICENSE("GPL v2");
|