debug.c 7.3 KB
Newer Older
1
#include <linux/kernel.h>
2 3 4
#include <linux/device.h>
#include <linux/types.h>
#include <linux/spinlock.h>
5 6 7
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
8 9 10 11 12 13 14 15 16
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>

#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "debug.h"

/**
17
 * ci_device_show: prints information about device capabilities and status
18
 */
19
static int ci_device_show(struct seq_file *s, void *data)
20
{
21
	struct ci_hdrc *ci = s->private;
22
	struct usb_gadget *gadget = &ci->gadget;
23

24 25 26 27 28 29 30 31 32 33 34 35
	seq_printf(s, "speed             = %d\n", gadget->speed);
	seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
	seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
	seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
	seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
	seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
	seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
	seq_printf(s, "name              = %s\n",
		   (gadget->name ? gadget->name : ""));

	if (!ci->driver)
		return 0;
36

37 38 39
	seq_printf(s, "gadget function   = %s\n",
		       (ci->driver->function ? ci->driver->function : ""));
	seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
40 41 42 43

	return 0;
}

44
static int ci_device_open(struct inode *inode, struct file *file)
45
{
46
	return single_open(file, ci_device_show, inode->i_private);
47 48
}

49 50 51 52 53 54
static const struct file_operations ci_device_fops = {
	.open		= ci_device_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
55 56

/**
57
 * ci_port_test_show: reads port test mode
58
 */
59
static int ci_port_test_show(struct seq_file *s, void *data)
60
{
61
	struct ci_hdrc *ci = s->private;
62 63 64
	unsigned long flags;
	unsigned mode;

65 66 67
	spin_lock_irqsave(&ci->lock, flags);
	mode = hw_port_test_get(ci);
	spin_unlock_irqrestore(&ci->lock, flags);
68

69 70 71
	seq_printf(s, "mode = %u\n", mode);

	return 0;
72 73 74
}

/**
75
 * ci_port_test_write: writes port test mode
76
 */
77 78
static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
				  size_t count, loff_t *ppos)
79
{
80
	struct seq_file *s = file->private_data;
81
	struct ci_hdrc *ci = s->private;
82 83
	unsigned long flags;
	unsigned mode;
84 85
	char buf[32];
	int ret;
86

87 88
	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;
89

90 91
	if (sscanf(buf, "%u", &mode) != 1)
		return -EINVAL;
92

93
	spin_lock_irqsave(&ci->lock, flags);
94
	ret = hw_port_test_set(ci, mode);
95
	spin_unlock_irqrestore(&ci->lock, flags);
96

97
	return ret ? ret : count;
98
}
99 100 101 102 103 104 105 106 107 108 109 110 111

static int ci_port_test_open(struct inode *inode, struct file *file)
{
	return single_open(file, ci_port_test_show, inode->i_private);
}

static const struct file_operations ci_port_test_fops = {
	.open		= ci_port_test_open,
	.write		= ci_port_test_write,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
112 113

/**
114
 * ci_qheads_show: DMA contents of all queue heads
115
 */
116
static int ci_qheads_show(struct seq_file *s, void *data)
117
{
118
	struct ci_hdrc *ci = s->private;
119
	unsigned long flags;
120
	unsigned i, j;
121

122 123
	if (ci->role != CI_ROLE_GADGET) {
		seq_printf(s, "not in gadget mode\n");
124 125 126
		return 0;
	}

127 128
	spin_lock_irqsave(&ci->lock, flags);
	for (i = 0; i < ci->hw_ep_max/2; i++) {
129 130 131
		struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
		struct ci_hw_ep *hweptx =
			&ci->ci_hw_ep[i + ci->hw_ep_max/2];
132
		seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
133
			   i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
134
		for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
135
			seq_printf(s, " %04X:    %08X    %08X\n", j,
136 137
				   *((u32 *)hweprx->qh.ptr + j),
				   *((u32 *)hweptx->qh.ptr + j));
138
	}
139
	spin_unlock_irqrestore(&ci->lock, flags);
140

141
	return 0;
142 143
}

144
static int ci_qheads_open(struct inode *inode, struct file *file)
145
{
146
	return single_open(file, ci_qheads_show, inode->i_private);
147 148
}

149 150 151 152 153 154
static const struct file_operations ci_qheads_fops = {
	.open		= ci_qheads_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
155 156

/**
157
 * ci_requests_show: DMA contents of all requests currently queued (all endpts)
158
 */
159
static int ci_requests_show(struct seq_file *s, void *data)
160
{
161
	struct ci_hdrc *ci = s->private;
162 163
	unsigned long flags;
	struct list_head   *ptr = NULL;
164
	struct ci_hw_req *req = NULL;
165
	struct td_node *node, *tmpnode;
166
	unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
167

168 169
	if (ci->role != CI_ROLE_GADGET) {
		seq_printf(s, "not in gadget mode\n");
170 171 172
		return 0;
	}

173 174
	spin_lock_irqsave(&ci->lock, flags);
	for (i = 0; i < ci->hw_ep_max; i++)
175 176
		list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
			req = list_entry(ptr, struct ci_hw_req, queue);
177

178 179 180 181 182 183 184 185 186 187 188
			list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
				seq_printf(s, "EP=%02i: TD=%08X %s\n",
					   i % (ci->hw_ep_max / 2),
					   (u32)node->dma,
					   ((i < ci->hw_ep_max/2) ?
					   "RX" : "TX"));

				for (j = 0; j < qsize; j++)
					seq_printf(s, " %04X:    %08X\n", j,
						   *((u32 *)node->ptr + j));
			}
189
		}
190
	spin_unlock_irqrestore(&ci->lock, flags);
191

192 193 194 195 196 197
	return 0;
}

static int ci_requests_open(struct inode *inode, struct file *file)
{
	return single_open(file, ci_requests_show, inode->i_private);
198
}
199 200 201 202 203 204 205

static const struct file_operations ci_requests_fops = {
	.open		= ci_requests_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
206

207 208
static int ci_role_show(struct seq_file *s, void *data)
{
209
	struct ci_hdrc *ci = s->private;
210 211 212 213 214 215 216 217 218 219

	seq_printf(s, "%s\n", ci_role(ci)->name);

	return 0;
}

static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
			     size_t count, loff_t *ppos)
{
	struct seq_file *s = file->private_data;
220
	struct ci_hdrc *ci = s->private;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
	enum ci_role role;
	char buf[8];
	int ret;

	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
		if (ci->roles[role] &&
		    !strncmp(buf, ci->roles[role]->name,
			     strlen(ci->roles[role]->name)))
			break;

	if (role == CI_ROLE_END || role == ci->role)
		return -EINVAL;

	ci_role_stop(ci);
	ret = ci_role_start(ci, role);

	return ret ? ret : count;
}

static int ci_role_open(struct inode *inode, struct file *file)
{
	return single_open(file, ci_role_show, inode->i_private);
}

static const struct file_operations ci_role_fops = {
	.open		= ci_role_open,
	.write		= ci_role_write,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

256 257
/**
 * dbg_create_files: initializes the attribute interface
258
 * @ci: device
259 260 261
 *
 * This function returns an error code
 */
262
int dbg_create_files(struct ci_hdrc *ci)
263
{
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	struct dentry *dent;

	ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
	if (!ci->debugfs)
		return -ENOMEM;

	dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
				   &ci_device_fops);
	if (!dent)
		goto err;

	dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
				   ci, &ci_port_test_fops);
	if (!dent)
		goto err;

	dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
				   &ci_qheads_fops);
	if (!dent)
		goto err;

	dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
				   &ci_requests_fops);
287 288 289 290 291
	if (!dent)
		goto err;

	dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
				   &ci_role_fops);
292 293 294 295 296
	if (dent)
		return 0;
err:
	debugfs_remove_recursive(ci->debugfs);
	return -ENOMEM;
297 298 299 300
}

/**
 * dbg_remove_files: destroys the attribute interface
301
 * @ci: device
302
 */
303
void dbg_remove_files(struct ci_hdrc *ci)
304
{
305
	debugfs_remove_recursive(ci->debugfs);
306
}