debug.c 7.2 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 22
	struct ci13xxx *ci = s->private;
	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 ci13xxx *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 81
	struct seq_file *s = file->private_data;
	struct ci13xxx *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 ci13xxx *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 129
	spin_lock_irqsave(&ci->lock, flags);
	for (i = 0; i < ci->hw_ep_max/2; i++) {
		struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
130
		struct ci13xxx_ep *mEpTx =
131
			&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
132 133 134 135 136 137
		seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
			   i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
			seq_printf(s, " %04X:    %08X    %08X\n", j,
				   *((u32 *)mEpRx->qh.ptr + j),
				   *((u32 *)mEpTx->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 ci13xxx *ci = s->private;
162 163 164
	unsigned long flags;
	struct list_head   *ptr = NULL;
	struct ci13xxx_req *req = NULL;
165
	unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
166

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

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

177
			seq_printf(s, "EP=%02i: TD=%08X %s\n",
178
				   i % (ci->hw_ep_max / 2), (u32)req->dma,
179
				   ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
180

181 182 183
			for (j = 0; j < qsize; j++)
				seq_printf(s, " %04X:    %08X\n", j,
					   *((u32 *)req->ptr + j));
184
		}
185
	spin_unlock_irqrestore(&ci->lock, flags);
186

187 188 189 190 191 192
	return 0;
}

static int ci_requests_open(struct inode *inode, struct file *file)
{
	return single_open(file, ci_requests_show, inode->i_private);
193
}
194 195 196 197 198 199 200

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

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 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
static int ci_role_show(struct seq_file *s, void *data)
{
	struct ci13xxx *ci = s->private;

	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;
	struct ci13xxx *ci = s->private;
	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,
};

251 252
/**
 * dbg_create_files: initializes the attribute interface
253
 * @ci: device
254 255 256
 *
 * This function returns an error code
 */
257
int dbg_create_files(struct ci13xxx *ci)
258
{
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
	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);
282 283 284 285 286
	if (!dent)
		goto err;

	dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
				   &ci_role_fops);
287 288 289 290 291
	if (dent)
		return 0;
err:
	debugfs_remove_recursive(ci->debugfs);
	return -ENOMEM;
292 293 294 295
}

/**
 * dbg_remove_files: destroys the attribute interface
296
 * @ci: device
297
 */
298
void dbg_remove_files(struct ci13xxx *ci)
299
{
300
	debugfs_remove_recursive(ci->debugfs);
301
}