debugfs.c 23.3 KB
Newer Older
1 2 3 4 5
#include <linux/module.h>
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/mm.h>
6
#include <linux/string.h>
7
#include <net/iw_handler.h>
8

9 10 11
#include "dev.h"
#include "decl.h"
#include "host.h"
12
#include "debugfs.h"
13
#include "cmd.h"
14

15
static struct dentry *lbs_dir;
16 17 18 19 20
static char *szStates[] = {
	"Connected",
	"Disconnected"
};

21
#ifdef PROC_DEBUG
22
static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev);
23
#endif
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

static int open_file_generic(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t write_file_dummy(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
        return -EINVAL;
}

static const size_t len = PAGE_SIZE;

39
static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
40 41
				  size_t count, loff_t *ppos)
{
42
	struct lbs_private *priv = file->private_data;
43 44 45 46 47 48
	size_t pos = 0;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	ssize_t res;

	pos += snprintf(buf+pos, len-pos, "state = %s\n",
49
				szStates[priv->connect_status]);
50
	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
51
				(u32) priv->regioncode);
52 53 54 55 56 57 58 59

	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

	free_page(addr);
	return res;
}


60
static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
61 62
				  size_t count, loff_t *ppos)
{
63
	struct lbs_private *priv = file->private_data;
64 65 66 67
	size_t pos = 0;
	int numscansdone = 0, res;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
68
	DECLARE_MAC_BUF(mac);
69
	struct bss_descriptor * iter_bss;
70 71

	pos += snprintf(buf+pos, len-pos,
72
		"# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");
73

74 75
	mutex_lock(&priv->lock);
	list_for_each_entry (iter_bss, &priv->network_list, list) {
76 77 78
		u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
		u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
		u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
79 80

		pos += snprintf(buf+pos, len-pos,
81
			"%02u| %03d | %04ld | %s |",
82
			numscansdone, iter_bss->channel, iter_bss->rssi,
83
			print_mac(mac, iter_bss->bssid));
84
		pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
85
		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
86 87
				ibss ? 'A' : 'I', privacy ? 'P' : ' ',
				spectrum_mgmt ? 'S' : ' ');
88
		pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
89 90
		pos += snprintf(buf+pos, len-pos, " %s\n",
		                escape_essid(iter_bss->ssid, iter_bss->ssid_len));
91 92 93

		numscansdone++;
	}
94
	mutex_unlock(&priv->lock);
95 96 97 98 99 100 101

	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

	free_page(addr);
	return res;
}

102
static ssize_t lbs_sleepparams_write(struct file *file,
103 104 105
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
106
	struct lbs_private *priv = file->private_data;
107 108
	ssize_t buf_size, ret;
	struct sleep_params sp;
109 110 111 112 113 114
	int p1, p2, p3, p4, p5, p6;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, user_buf, buf_size)) {
115
		ret = -EFAULT;
116 117
		goto out_unlock;
	}
118 119 120
	ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
	if (ret != 6) {
		ret = -EINVAL;
121 122
		goto out_unlock;
	}
123 124 125 126 127 128 129 130 131 132 133 134
	sp.sp_error = p1;
	sp.sp_offset = p2;
	sp.sp_stabletime = p3;
	sp.sp_calcontrol = p4;
	sp.sp_extsleepclk = p5;
	sp.sp_reserved = p6;

	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
	if (!ret)
		ret = count;
	else if (ret > 0)
		ret = -EINVAL;
135 136 137

out_unlock:
	free_page(addr);
138
	return ret;
139 140
}

141
static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
142 143
				  size_t count, loff_t *ppos)
{
144
	struct lbs_private *priv = file->private_data;
145
	ssize_t ret;
146
	size_t pos = 0;
147
	struct sleep_params sp;
148 149 150
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

151 152
	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
	if (ret)
153 154
		goto out_unlock;

155 156 157 158
	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
			sp.sp_offset, sp.sp_stabletime,
			sp.sp_calcontrol, sp.sp_extsleepclk,
			sp.sp_reserved);
159

160
	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
161 162 163

out_unlock:
	free_page(addr);
164
	return ret;
165 166
}

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/*
 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
 * firmware. Here's an example:
 *	04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
 *	00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
 *	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 *
 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
 * defined in mrvlietypes_thresholds
 *
 * This function searches in this TLV data chunk for a given TLV type
 * and returns a pointer to the first data byte of the TLV, or to NULL
 * if the TLV hasn't been found.
 */
183
static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
184
{
185
	struct mrvlietypesheader *tlv_h;
186 187 188
	uint16_t length;
	ssize_t pos = 0;

189 190
	while (pos < size) {
		tlv_h = (struct mrvlietypesheader *) tlv;
191
		if (!tlv_h->len)
192
			return NULL;
193 194 195
		if (tlv_h->type == cpu_to_le16(tlv_type))
			return tlv_h;
		length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
196 197 198 199
		pos += length;
		tlv += length;
	}
	return NULL;
200 201
}

202

203 204 205
static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
				  struct file *file, char __user *userbuf,
				  size_t count, loff_t *ppos)
206
{
207 208
	struct cmd_ds_802_11_subscribe_event *subscribed;
	struct mrvlietypes_thresholds *got;
209
	struct lbs_private *priv = file->private_data;
210
	ssize_t ret = 0;
211
	size_t pos = 0;
212
	char *buf;
213 214
	u8 value;
	u8 freq;
215
	int events = 0;
216

217 218 219
	buf = (char *)get_zeroed_page(GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
220

221 222 223 224
	subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
	if (!subscribed) {
		ret = -ENOMEM;
		goto out_page;
225 226
	}

227 228 229 230 231 232 233
	subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
	subscribed->action = cpu_to_le16(CMD_ACT_GET);

	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
	if (ret)
		goto out_cmd;

234
	got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
235 236 237
	if (got) {
		value = got->value;
		freq  = got->freq;
238
		events = le16_to_cpu(subscribed->events);
239

240
		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
241 242
				!!(events & event_mask));
	}
243

244
	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
245

246 247 248 249 250 251
 out_cmd:
	kfree(subscribed);

 out_page:
	free_page((unsigned long)buf);
	return ret;
252 253 254
}


255 256 257 258
static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
				   struct file *file,
				   const char __user *userbuf, size_t count,
				   loff_t *ppos)
259
{
260
	struct cmd_ds_802_11_subscribe_event *events;
261 262 263 264 265 266 267 268 269 270 271
	struct mrvlietypes_thresholds *tlv;
	struct lbs_private *priv = file->private_data;
	ssize_t buf_size;
	int value, freq, new_mask;
	uint16_t curr_mask;
	char *buf;
	int ret;

	buf = (char *)get_zeroed_page(GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
272 273 274

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
275 276
		ret = -EFAULT;
		goto out_page;
277
	}
278 279 280 281 282 283 284 285 286
	ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
	if (ret != 3) {
		ret = -EINVAL;
		goto out_page;
	}
	events = kzalloc(sizeof(*events), GFP_KERNEL);
	if (!events) {
		ret = -ENOMEM;
		goto out_page;
287
	}
288 289 290 291 292 293 294 295 296

	events->hdr.size = cpu_to_le16(sizeof(*events));
	events->action = cpu_to_le16(CMD_ACT_GET);

	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
	if (ret)
		goto out_events;

	curr_mask = le16_to_cpu(events->events);
297

298 299 300 301 302 303
	if (new_mask)
		new_mask = curr_mask | event_mask;
	else
		new_mask = curr_mask & ~event_mask;

	/* Now everything is set and we can send stuff down to the firmware */
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	tlv = (void *)events->tlv;

	events->action = cpu_to_le16(CMD_ACT_SET);
	events->events = cpu_to_le16(new_mask);
	tlv->header.type = cpu_to_le16(tlv_type);
	tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
	tlv->value = value;
	if (tlv_type != TLV_TYPE_BCNMISS)
		tlv->freq = freq;

	/* The command header, the event mask, and the one TLV */
	events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv));

	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);

	if (!ret)
		ret = count;
 out_events:
	kfree(events);
 out_page:
	free_page((unsigned long)buf);
	return ret;
327 328 329
}


330 331
static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
332
{
333
	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
334
				  file, userbuf, count, ppos);
335 336 337
}


338 339
static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
				 size_t count, loff_t *ppos)
340 341
{
	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
342
				   file, userbuf, count, ppos);
343
}
344 345


346 347
static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
			       size_t count, loff_t *ppos)
348 349
{
	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
350
				  file, userbuf, count, ppos);
351
}
352 353


354 355
static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
				size_t count, loff_t *ppos)
356 357
{
	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
358
				   file, userbuf, count, ppos);
359
}
360 361


362 363
static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
				  size_t count, loff_t *ppos)
364 365
{
	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
366
				  file, userbuf, count, ppos);
367
}
368 369


370 371
static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
				   size_t count, loff_t *ppos)
372 373
{
	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
374
				   file, userbuf, count, ppos);
375 376
}

377

378 379
static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
				 size_t count, loff_t *ppos)
380
{
381
	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
382
				  file, userbuf, count, ppos);
383
}
384 385


386 387
static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
				  size_t count, loff_t *ppos)
388 389
{
	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
390
				   file, userbuf, count, ppos);
391
}
392 393


394 395
static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
396 397
{
	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
398
				  file, userbuf, count, ppos);
399
}
400 401


402 403
static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
				 size_t count, loff_t *ppos)
404 405
{
	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
406
				   file, userbuf, count, ppos);
407 408
}

409 410
static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
411
{
412
	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
413
				  file, userbuf, count, ppos);
414
}
415 416


417 418
static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
				 size_t count, loff_t *ppos)
419 420
{
	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
421
				   file, userbuf, count, ppos);
422 423 424 425
}



426
static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
427 428
				  size_t count, loff_t *ppos)
{
429
	struct lbs_private *priv = file->private_data;
430
	struct lbs_offset_value offval;
431 432 433 434 435 436 437 438
	ssize_t pos = 0;
	int ret;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	offval.offset = priv->mac_offset;
	offval.value = 0;

439
	ret = lbs_prepare_and_send_command(priv,
440 441
				CMD_MAC_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
442 443
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
444
				priv->mac_offset, priv->offsetvalue.value);
445 446 447 448 449 450

	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
	free_page(addr);
	return ret;
}

451
static ssize_t lbs_rdmac_write(struct file *file,
452 453 454
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
455
	struct lbs_private *priv = file->private_data;
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
	ssize_t res, buf_size;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
	res = count;
out_unlock:
	free_page(addr);
	return res;
}

472
static ssize_t lbs_wrmac_write(struct file *file,
473 474 475 476
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

477
	struct lbs_private *priv = file->private_data;
478 479
	ssize_t res, buf_size;
	u32 offset, value;
480
	struct lbs_offset_value offval;
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	res = sscanf(buf, "%x %x", &offset, &value);
	if (res != 2) {
		res = -EFAULT;
		goto out_unlock;
	}

	offval.offset = offset;
	offval.value = value;
497
	res = lbs_prepare_and_send_command(priv,
498 499
				CMD_MAC_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
500 501 502 503 504 505 506 507
	mdelay(10);

	res = count;
out_unlock:
	free_page(addr);
	return res;
}

508
static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
509 510
				  size_t count, loff_t *ppos)
{
511
	struct lbs_private *priv = file->private_data;
512
	struct lbs_offset_value offval;
513 514 515 516 517 518 519 520
	ssize_t pos = 0;
	int ret;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	offval.offset = priv->bbp_offset;
	offval.value = 0;

521
	ret = lbs_prepare_and_send_command(priv,
522 523
				CMD_BBP_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
524 525
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
526
				priv->bbp_offset, priv->offsetvalue.value);
527 528 529 530 531 532 533

	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
	free_page(addr);

	return ret;
}

534
static ssize_t lbs_rdbbp_write(struct file *file,
535 536 537
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
538
	struct lbs_private *priv = file->private_data;
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
	ssize_t res, buf_size;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
	res = count;
out_unlock:
	free_page(addr);
	return res;
}

555
static ssize_t lbs_wrbbp_write(struct file *file,
556 557 558 559
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

560
	struct lbs_private *priv = file->private_data;
561 562
	ssize_t res, buf_size;
	u32 offset, value;
563
	struct lbs_offset_value offval;
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	res = sscanf(buf, "%x %x", &offset, &value);
	if (res != 2) {
		res = -EFAULT;
		goto out_unlock;
	}

	offval.offset = offset;
	offval.value = value;
580
	res = lbs_prepare_and_send_command(priv,
581 582
				CMD_BBP_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
583 584 585 586 587 588 589 590
	mdelay(10);

	res = count;
out_unlock:
	free_page(addr);
	return res;
}

591
static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
592 593
				  size_t count, loff_t *ppos)
{
594
	struct lbs_private *priv = file->private_data;
595
	struct lbs_offset_value offval;
596 597 598 599 600 601 602 603
	ssize_t pos = 0;
	int ret;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	offval.offset = priv->rf_offset;
	offval.value = 0;

604
	ret = lbs_prepare_and_send_command(priv,
605 606
				CMD_RF_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
607 608
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
609
				priv->rf_offset, priv->offsetvalue.value);
610 611 612 613 614 615 616

	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
	free_page(addr);

	return ret;
}

617
static ssize_t lbs_rdrf_write(struct file *file,
618 619 620
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
621
	struct lbs_private *priv = file->private_data;
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
	ssize_t res, buf_size;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
	res = count;
out_unlock:
	free_page(addr);
	return res;
}

638
static ssize_t lbs_wrrf_write(struct file *file,
639 640 641 642
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

643
	struct lbs_private *priv = file->private_data;
644 645
	ssize_t res, buf_size;
	u32 offset, value;
646
	struct lbs_offset_value offval;
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
	res = sscanf(buf, "%x %x", &offset, &value);
	if (res != 2) {
		res = -EFAULT;
		goto out_unlock;
	}

	offval.offset = offset;
	offval.value = value;
663
	res = lbs_prepare_and_send_command(priv,
664 665
				CMD_RF_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
	mdelay(10);

	res = count;
out_unlock:
	free_page(addr);
	return res;
}

#define FOPS(fread, fwrite) { \
	.owner = THIS_MODULE, \
	.open = open_file_generic, \
	.read = (fread), \
	.write = (fwrite), \
}

681
struct lbs_debugfs_files {
682 683 684 685 686
	char *name;
	int perm;
	struct file_operations fops;
};

687 688 689
static struct lbs_debugfs_files debugfs_files[] = {
	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
	{ "getscantable", 0444, FOPS(lbs_getscantable,
690
					write_file_dummy), },
691 692
	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
				lbs_sleepparams_write), },
693 694
};

695 696 697 698 699 700 701 702 703 704 705 706 707
static struct lbs_debugfs_files debugfs_events_files[] = {
	{"low_rssi", 0644, FOPS(lbs_lowrssi_read,
				lbs_lowrssi_write), },
	{"low_snr", 0644, FOPS(lbs_lowsnr_read,
				lbs_lowsnr_write), },
	{"failure_count", 0644, FOPS(lbs_failcount_read,
				lbs_failcount_write), },
	{"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
				lbs_bcnmiss_write), },
	{"high_rssi", 0644, FOPS(lbs_highrssi_read,
				lbs_highrssi_write), },
	{"high_snr", 0644, FOPS(lbs_highsnr_read,
				lbs_highsnr_write), },
708 709
};

710 711 712 713 714 715 716
static struct lbs_debugfs_files debugfs_regs_files[] = {
	{"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
	{"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
	{"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
	{"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
	{"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
	{"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
717 718
};

719
void lbs_debugfs_init(void)
720
{
721 722
	if (!lbs_dir)
		lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
723 724 725 726

	return;
}

727
void lbs_debugfs_remove(void)
728
{
729 730
	if (lbs_dir)
		 debugfs_remove(lbs_dir);
731 732 733
	return;
}

734
void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
735 736
{
	int i;
737 738
	struct lbs_debugfs_files *files;
	if (!lbs_dir)
739 740
		goto exit;

741
	priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
	if (!priv->debugfs_dir)
		goto exit;

	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
		files = &debugfs_files[i];
		priv->debugfs_files[i] = debugfs_create_file(files->name,
							     files->perm,
							     priv->debugfs_dir,
							     priv,
							     &files->fops);
	}

	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
	if (!priv->events_dir)
		goto exit;

	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
		files = &debugfs_events_files[i];
		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
							     files->perm,
							     priv->events_dir,
							     priv,
							     &files->fops);
	}

	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
	if (!priv->regs_dir)
		goto exit;

	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
		files = &debugfs_regs_files[i];
		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
							     files->perm,
							     priv->regs_dir,
							     priv,
							     &files->fops);
	}

#ifdef PROC_DEBUG
781
	lbs_debug_init(priv, dev);
782 783 784 785 786
#endif
exit:
	return;
}

787
void lbs_debugfs_remove_one(struct lbs_private *priv)
788 789 790 791 792 793 794 795
{
	int i;

	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
		debugfs_remove(priv->debugfs_regs_files[i]);

	debugfs_remove(priv->regs_dir);

796
	for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
797 798 799 800 801 802 803 804
		debugfs_remove(priv->debugfs_events_files[i]);

	debugfs_remove(priv->events_dir);
#ifdef PROC_DEBUG
	debugfs_remove(priv->debugfs_debug);
#endif
	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
		debugfs_remove(priv->debugfs_files[i]);
805
	debugfs_remove(priv->debugfs_dir);
806 807
}

808 809


810 811
/* debug entry */

812 813
#ifdef PROC_DEBUG

814 815
#define item_size(n)	(FIELD_SIZEOF(struct lbs_private, n))
#define item_addr(n)	(offsetof(struct lbs_private, n))
816

817

818 819 820
struct debug_data {
	char name[32];
	u32 size;
D
Dan Williams 已提交
821
	size_t addr;
822 823
};

824
/* To debug any member of struct lbs_private, simply add one line here.
825 826 827 828 829 830 831
 */
static struct debug_data items[] = {
	{"intcounter", item_size(intcounter), item_addr(intcounter)},
	{"psmode", item_size(psmode), item_addr(psmode)},
	{"psstate", item_size(psstate), item_addr(psstate)},
};

832
static int num_of_items = ARRAY_SIZE(items);
833 834 835 836 837 838 839 840 841 842 843 844

/**
 *  @brief proc read function
 *
 *  @param page	   pointer to buffer
 *  @param s       read data starting position
 *  @param off     offset
 *  @param cnt     counter
 *  @param eof     end of file flag
 *  @param data    data to output
 *  @return 	   number of output data
 */
845
static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
			size_t count, loff_t *ppos)
{
	int val = 0;
	size_t pos = 0;
	ssize_t res;
	char *p;
	int i;
	struct debug_data *d;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

	p = buf;

	d = (struct debug_data *)file->private_data;

	for (i = 0; i < num_of_items; i++) {
		if (d[i].size == 1)
			val = *((u8 *) d[i].addr);
		else if (d[i].size == 2)
			val = *((u16 *) d[i].addr);
		else if (d[i].size == 4)
			val = *((u32 *) d[i].addr);
D
Dan Williams 已提交
868 869
		else if (d[i].size == 8)
			val = *((u64 *) d[i].addr);
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888

		pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
	}

	res = simple_read_from_buffer(userbuf, count, ppos, p, pos);

	free_page(addr);
	return res;
}

/**
 *  @brief proc write function
 *
 *  @param f	   file pointer
 *  @param buf     pointer to data buffer
 *  @param cnt     data number to write
 *  @param data    data to write
 *  @return 	   number of data
 */
889
static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
890 891 892 893 894 895 896 897 898 899
			    size_t cnt, loff_t *ppos)
{
	int r, i;
	char *pdata;
	char *p;
	char *p0;
	char *p1;
	char *p2;
	struct debug_data *d = (struct debug_data *)f->private_data;

900
	pdata = kmalloc(cnt, GFP_KERNEL);
901 902 903 904
	if (pdata == NULL)
		return 0;

	if (copy_from_user(pdata, buf, cnt)) {
905
		lbs_deb_debugfs("Copy from user failed\n");
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
		kfree(pdata);
		return 0;
	}

	p0 = pdata;
	for (i = 0; i < num_of_items; i++) {
		do {
			p = strstr(p0, d[i].name);
			if (p == NULL)
				break;
			p1 = strchr(p, '\n');
			if (p1 == NULL)
				break;
			p0 = p1++;
			p2 = strchr(p, '=');
			if (!p2)
				break;
			p2++;
924
			r = simple_strtoul(p2, NULL, 0);
925 926 927 928 929 930
			if (d[i].size == 1)
				*((u8 *) d[i].addr) = (u8) r;
			else if (d[i].size == 2)
				*((u16 *) d[i].addr) = (u16) r;
			else if (d[i].size == 4)
				*((u32 *) d[i].addr) = (u32) r;
D
Dan Williams 已提交
931 932
			else if (d[i].size == 8)
				*((u64 *) d[i].addr) = (u64) r;
933 934 935 936 937
			break;
		} while (1);
	}
	kfree(pdata);

D
Dan Williams 已提交
938
	return (ssize_t)cnt;
939 940
}

941
static struct file_operations lbs_debug_fops = {
942 943
	.owner = THIS_MODULE,
	.open = open_file_generic,
944 945
	.write = lbs_debugfs_write,
	.read = lbs_debugfs_read,
946 947 948 949 950
};

/**
 *  @brief create debug proc file
 *
951
 *  @param priv	   pointer struct lbs_private
952 953 954
 *  @param dev     pointer net_device
 *  @return 	   N/A
 */
955
static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
956 957 958 959 960 961 962
{
	int i;

	if (!priv->debugfs_dir)
		return;

	for (i = 0; i < num_of_items; i++)
963
		items[i].addr += (size_t) priv;
964 965 966

	priv->debugfs_debug = debugfs_create_file("debug", 0644,
						  priv->debugfs_dir, &items[0],
967
						  &lbs_debug_fops);
968
}
969
#endif