debugfs.c 27.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

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

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

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;

38
static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
39 40
				  size_t count, loff_t *ppos)
{
41
	struct lbs_private *priv = file->private_data;
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
	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",
				szStates[priv->adapter->connect_status]);
	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
				(u32) priv->adapter->regioncode);

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

	free_page(addr);
	return res;
}


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

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

73 74
	mutex_lock(&priv->adapter->lock);
	list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
75 76 77
		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);
78 79

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

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

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

	free_page(addr);
	return res;
}

101
static ssize_t lbs_sleepparams_write(struct file *file,
102 103 104
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
105
	struct lbs_private *priv = file->private_data;
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
	ssize_t buf_size, res;
	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)) {
		res = -EFAULT;
		goto out_unlock;
	}
	res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
	if (res != 6) {
		res = -EFAULT;
		goto out_unlock;
	}
121 122 123 124 125 126
	priv->adapter->sp.sp_error = p1;
	priv->adapter->sp.sp_offset = p2;
	priv->adapter->sp.sp_stabletime = p3;
	priv->adapter->sp.sp_calcontrol = p4;
	priv->adapter->sp.sp_extsleepclk = p5;
	priv->adapter->sp.sp_reserved = p6;
127

128
	res = lbs_prepare_and_send_command(priv,
129 130 131
				CMD_802_11_SLEEP_PARAMS,
				CMD_ACT_SET,
				CMD_OPTION_WAITFORRSP, 0, NULL);
132 133 134 135 136 137 138 139 140 141 142

	if (!res)
		res = count;
	else
		res = -EINVAL;

out_unlock:
	free_page(addr);
	return res;
}

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

153
	res = lbs_prepare_and_send_command(priv,
154 155 156
				CMD_802_11_SLEEP_PARAMS,
				CMD_ACT_GET,
				CMD_OPTION_WAITFORRSP, 0, NULL);
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	if (res) {
		res = -EFAULT;
		goto out_unlock;
	}

	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
			adapter->sp.sp_offset, adapter->sp.sp_stabletime,
			adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
			adapter->sp.sp_reserved);

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

out_unlock:
	free_page(addr);
	return res;
}

174
static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
175 176
				  size_t count, loff_t *ppos)
{
177
	struct lbs_private *priv = file->private_data;
178 179 180 181 182 183 184 185 186 187 188
	ssize_t res, buf_size;
	union iwreq_data wrqu;
	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;
	}

189
	lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
190 191

	memset(&wrqu, 0, sizeof(union iwreq_data));
192
	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
193 194 195 196 197 198

out_unlock:
	free_page(addr);
	return count;
}

199 200
static void lbs_parse_bssid(char *buf, size_t count,
	struct lbs_ioctl_user_scan_cfg *scan_cfg)
201 202 203 204 205 206 207 208
{
	char *hold;
	unsigned int mac[ETH_ALEN];

	hold = strstr(buf, "bssid=");
	if (!hold)
		return;
	hold += 6;
209 210
	sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x",
	       mac, mac+1, mac+2, mac+3, mac+4, mac+5);
211
	memcpy(scan_cfg->bssid, mac, ETH_ALEN);
212 213
}

214 215
static void lbs_parse_ssid(char *buf, size_t count,
	struct lbs_ioctl_user_scan_cfg *scan_cfg)
216 217 218 219 220 221 222 223
{
	char *hold, *end;
	ssize_t size;

	hold = strstr(buf, "ssid=");
	if (!hold)
		return;
	hold += 5;
224
	end = strchr(hold, ' ');
225 226 227
	if (!end)
		end = buf + count - 1;

D
Dan Williams 已提交
228
	size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
229
	strncpy(scan_cfg->ssid, hold, size);
230 231 232 233

	return;
}

234
static int lbs_parse_clear(char *buf, size_t count, const char *tag)
235 236 237 238
{
	char *hold;
	int val;

239
	hold = strstr(buf, tag);
240
	if (!hold)
241 242
		return 0;
	hold += strlen(tag);
243 244 245 246 247
	sscanf(hold, "%d", &val);

	if (val != 0)
		val = 1;

248
	return val;
249 250
}

251 252
static int lbs_parse_dur(char *buf, size_t count,
	struct lbs_ioctl_user_scan_cfg *scan_cfg)
253 254 255 256 257 258 259 260 261 262 263 264 265
{
	char *hold;
	int val;

	hold = strstr(buf, "dur=");
	if (!hold)
		return 0;
	hold += 4;
	sscanf(hold, "%d", &val);

	return val;
}

266 267
static void lbs_parse_type(char *buf, size_t count,
	struct lbs_ioctl_user_scan_cfg *scan_cfg)
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
{
	char *hold;
	int val;

	hold = strstr(buf, "type=");
	if (!hold)
		return;
	hold += 5;
	sscanf(hold, "%d", &val);

	/* type=1,2 or 3 */
	if (val < 1 || val > 3)
		return;

	scan_cfg->bsstype = val;

	return;
}

287
static ssize_t lbs_setuserscan(struct file *file,
288 289 290
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
291
	struct lbs_private *priv = file->private_data;
292
	ssize_t res, buf_size;
293
	struct lbs_ioctl_user_scan_cfg *scan_cfg;
294 295
	union iwreq_data wrqu;
	int dur;
296
	char *buf = (char *)get_zeroed_page(GFP_KERNEL);
297

298
	if (!buf)
299
		return -ENOMEM;
300
		
301 302 303
	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
304
		goto out_buf;
305 306
	}

307 308 309 310 311 312 313
	scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
	if (!scan_cfg) {
		res = -ENOMEM;
		goto out_buf;
	}
	res = count;

314
	scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
315

316 317 318 319 320 321
	dur = lbs_parse_dur(buf, count, scan_cfg);
	lbs_parse_bssid(buf, count, scan_cfg);
	scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
	lbs_parse_ssid(buf, count, scan_cfg);
	scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
	lbs_parse_type(buf, count, scan_cfg);
322

323
	lbs_scan_networks(priv, scan_cfg, 1);
324
	wait_event_interruptible(priv->adapter->cmd_pending,
325 326
				 priv->adapter->surpriseremoved || 
				 (!priv->adapter->cur_cmd && list_empty(&priv->adapter->cmdpendingq)));
327 328 329

	if (priv->adapter->surpriseremoved)
		goto out_scan_cfg;
330 331

	memset(&wrqu, 0x00, sizeof(union iwreq_data));
332
	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
333

334
 out_scan_cfg:
335
	kfree(scan_cfg);
336 337 338
 out_buf:
	free_page((unsigned long)buf);
	return res;
339 340 341
}


342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
/*
 * 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.
 */
static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
359
{
360
	__le16 le_type = cpu_to_le16(tlv_type);
361
	ssize_t pos = 0;
362 363 364 365 366 367 368 369 370 371 372 373 374 375
	struct mrvlietypesheader *tlv_h;
	while (pos < size) {
		u16 length;
		tlv_h = (struct mrvlietypesheader *) tlv;
		if (tlv_h->type == le_type)
			return tlv_h;
		if (tlv_h->len == 0)
			return NULL;
		length = le16_to_cpu(tlv_h->len) +
			sizeof(struct mrvlietypesheader);
		pos += length;
		tlv += length;
	}
	return NULL;
376 377
}

378 379 380 381 382

/*
 * This just gets the bitmap of currently subscribed events. Used when
 * adding an additonal event subscription.
 */
383
static u16 lbs_get_events_bitmap(struct lbs_private *priv)
384
{
385
	ssize_t res;
386

387 388 389
	struct cmd_ds_802_11_subscribe_event *events = kzalloc(
		sizeof(struct cmd_ds_802_11_subscribe_event),
		GFP_KERNEL);
390

391 392 393
	res = lbs_prepare_and_send_command(priv,
			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
			CMD_OPTION_WAITFORRSP, 0, events);
394

395 396
	if (res) {
		kfree(events);
397 398
		return 0;
	}
399
	return le16_to_cpu(events->events);
400 401 402
}


403 404 405 406
static ssize_t lbs_threshold_read(
	u16 tlv_type, u16 event_mask,
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
407
{
408
	struct lbs_private *priv = file->private_data;
409 410
	ssize_t res = 0;
	size_t pos = 0;
411 412
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
413 414
	u8 value;
	u8 freq;
415

416 417 418 419
	struct cmd_ds_802_11_subscribe_event *events = kzalloc(
		sizeof(struct cmd_ds_802_11_subscribe_event),
		GFP_KERNEL);
	struct mrvlietypes_thresholds *got;
420

421 422 423 424 425 426
	res = lbs_prepare_and_send_command(priv,
			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
			CMD_OPTION_WAITFORRSP, 0, events);
	if (res) {
		kfree(events);
		return res;
427 428
	}

429 430 431 432
	got = lbs_tlv_find(tlv_type, events->tlv, sizeof(events->tlv));
	if (got) {
		value = got->value;
		freq  = got->freq;
433
	}
434
	kfree(events);
435

436 437 438
	if (got)
		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
			!!(le16_to_cpu(events->events) & event_mask));
439 440 441 442 443 444 445 446

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

	free_page(addr);
	return res;
}


447 448 449 450 451
static ssize_t lbs_threshold_write(
	u16 tlv_type, u16 event_mask,
	struct file *file,
	const char __user *userbuf,
	size_t count, loff_t *ppos)
452
{
453
	struct lbs_private *priv = file->private_data;
454
	ssize_t res, buf_size;
455
	int value, freq, curr_mask, new_mask;
456 457
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
458
	struct cmd_ds_802_11_subscribe_event *events;
459 460 461 462 463 464

	buf_size = min(count, len - 1);
	if (copy_from_user(buf, userbuf, buf_size)) {
		res = -EFAULT;
		goto out_unlock;
	}
465
	res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
466 467 468 469
	if (res != 3) {
		res = -EFAULT;
		goto out_unlock;
	}
470
	curr_mask = lbs_get_events_bitmap(priv);
471

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
	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 */
	events = kzalloc(
		sizeof(struct cmd_ds_802_11_subscribe_event),
		GFP_KERNEL);
	if (events) {
		struct mrvlietypes_thresholds *tlv =
			(struct mrvlietypes_thresholds *) 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(struct mrvlietypes_thresholds) -
			sizeof(struct mrvlietypesheader));
		tlv->value = value;
		if (tlv_type != TLV_TYPE_BCNMISS)
			tlv->freq = freq;
		lbs_prepare_and_send_command(priv,
			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
			CMD_OPTION_WAITFORRSP, 0, events);
		kfree(events);
497 498 499 500 501 502 503 504 505
	}

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


506 507 508
static ssize_t lbs_lowrssi_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
509
{
510 511
	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
		file, userbuf, count, ppos);
512 513 514
}


515 516 517 518 519 520 521
static ssize_t lbs_lowrssi_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
		file, userbuf, count, ppos);
}
522 523


524 525 526 527 528 529 530
static ssize_t lbs_lowsnr_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
		file, userbuf, count, ppos);
}
531 532


533 534 535 536 537 538 539
static ssize_t lbs_lowsnr_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
		file, userbuf, count, ppos);
}
540 541


542 543 544 545 546 547 548
static ssize_t lbs_failcount_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
		file, userbuf, count, ppos);
}
549 550


551 552 553 554 555 556
static ssize_t lbs_failcount_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
		file, userbuf, count, ppos);
557 558
}

559 560 561 562

static ssize_t lbs_highrssi_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
563
{
564 565 566
	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
		file, userbuf, count, ppos);
}
567 568


569 570 571 572 573 574 575
static ssize_t lbs_highrssi_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
		file, userbuf, count, ppos);
}
576 577


578 579 580 581 582 583 584
static ssize_t lbs_highsnr_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
		file, userbuf, count, ppos);
}
585 586


587 588 589 590 591 592
static ssize_t lbs_highsnr_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
		file, userbuf, count, ppos);
593 594
}

595 596 597
static ssize_t lbs_bcnmiss_read(
	struct file *file, char __user *userbuf,
	size_t count, loff_t *ppos)
598
{
599 600 601
	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
		file, userbuf, count, ppos);
}
602 603


604 605 606 607 608 609
static ssize_t lbs_bcnmiss_write(
	struct file *file, const char __user *userbuf,
	size_t count, loff_t *ppos)
{
	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
		file, userbuf, count, ppos);
610 611 612 613 614 615 616 617 618
}








619
static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
620 621
				  size_t count, loff_t *ppos)
{
622 623
	struct lbs_private *priv = file->private_data;
	struct lbs_adapter *adapter = priv->adapter;
624
	struct lbs_offset_value offval;
625 626 627 628 629 630 631 632
	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;

633
	ret = lbs_prepare_and_send_command(priv,
634 635
				CMD_MAC_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
636 637 638 639 640 641 642 643 644
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
				priv->mac_offset, adapter->offsetvalue.value);

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

645
static ssize_t lbs_rdmac_write(struct file *file,
646 647 648
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
649
	struct lbs_private *priv = file->private_data;
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
	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;
}

666
static ssize_t lbs_wrmac_write(struct file *file,
667 668 669 670
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

671
	struct lbs_private *priv = file->private_data;
672 673
	ssize_t res, buf_size;
	u32 offset, value;
674
	struct lbs_offset_value offval;
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
	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;
691
	res = lbs_prepare_and_send_command(priv,
692 693
				CMD_MAC_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
694 695 696 697 698 699 700 701
	mdelay(10);

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

702
static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
703 704
				  size_t count, loff_t *ppos)
{
705 706
	struct lbs_private *priv = file->private_data;
	struct lbs_adapter *adapter = priv->adapter;
707
	struct lbs_offset_value offval;
708 709 710 711 712 713 714 715
	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;

716
	ret = lbs_prepare_and_send_command(priv,
717 718
				CMD_BBP_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
719 720 721 722 723 724 725 726 727 728
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
				priv->bbp_offset, adapter->offsetvalue.value);

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

	return ret;
}

729
static ssize_t lbs_rdbbp_write(struct file *file,
730 731 732
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
733
	struct lbs_private *priv = file->private_data;
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
	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;
}

750
static ssize_t lbs_wrbbp_write(struct file *file,
751 752 753 754
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

755
	struct lbs_private *priv = file->private_data;
756 757
	ssize_t res, buf_size;
	u32 offset, value;
758
	struct lbs_offset_value offval;
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	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;
775
	res = lbs_prepare_and_send_command(priv,
776 777
				CMD_BBP_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
778 779 780 781 782 783 784 785
	mdelay(10);

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

786
static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
787 788
				  size_t count, loff_t *ppos)
{
789 790
	struct lbs_private *priv = file->private_data;
	struct lbs_adapter *adapter = priv->adapter;
791
	struct lbs_offset_value offval;
792 793 794 795 796 797 798 799
	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;

800
	ret = lbs_prepare_and_send_command(priv,
801 802
				CMD_RF_REG_ACCESS, 0,
				CMD_OPTION_WAITFORRSP, 0, &offval);
803 804 805 806 807 808 809 810 811 812
	mdelay(10);
	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
				priv->rf_offset, adapter->offsetvalue.value);

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

	return ret;
}

813
static ssize_t lbs_rdrf_write(struct file *file,
814 815 816
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{
817
	struct lbs_private *priv = file->private_data;
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
	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;
}

834
static ssize_t lbs_wrrf_write(struct file *file,
835 836 837 838
				    const char __user *userbuf,
				    size_t count, loff_t *ppos)
{

839
	struct lbs_private *priv = file->private_data;
840 841
	ssize_t res, buf_size;
	u32 offset, value;
842
	struct lbs_offset_value offval;
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
	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;
859
	res = lbs_prepare_and_send_command(priv,
860 861
				CMD_RF_REG_ACCESS, 1,
				CMD_OPTION_WAITFORRSP, 0, &offval);
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
	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), \
}

877
struct lbs_debugfs_files {
878 879 880 881 882
	char *name;
	int perm;
	struct file_operations fops;
};

883 884 885
static struct lbs_debugfs_files debugfs_files[] = {
	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
	{ "getscantable", 0444, FOPS(lbs_getscantable,
886
					write_file_dummy), },
887 888 889 890
	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
				lbs_sleepparams_write), },
	{ "extscan", 0600, FOPS(NULL, lbs_extscan), },
	{ "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
891 892
};

893 894 895 896 897 898 899 900 901 902 903 904 905
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), },
906 907
};

908 909 910 911 912 913 914
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), },
915 916
};

917
void lbs_debugfs_init(void)
918
{
919 920
	if (!lbs_dir)
		lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
921 922 923 924

	return;
}

925
void lbs_debugfs_remove(void)
926
{
927 928
	if (lbs_dir)
		 debugfs_remove(lbs_dir);
929 930 931
	return;
}

932
void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
933 934
{
	int i;
935 936
	struct lbs_debugfs_files *files;
	if (!lbs_dir)
937 938
		goto exit;

939
	priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
	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
979
	lbs_debug_init(priv, dev);
980 981 982 983 984
#endif
exit:
	return;
}

985
void lbs_debugfs_remove_one(struct lbs_private *priv)
986 987 988 989 990 991 992 993
{
	int i;

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

	debugfs_remove(priv->regs_dir);

994
	for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
995 996 997 998 999 1000 1001 1002
		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]);
1003
	debugfs_remove(priv->debugfs_dir);
1004 1005
}

1006 1007


1008 1009
/* debug entry */

1010 1011
#ifdef PROC_DEBUG

1012 1013
#define item_size(n)	(FIELD_SIZEOF(struct lbs_adapter, n))
#define item_addr(n)	(offsetof(struct lbs_adapter, n))
1014

1015

1016 1017 1018
struct debug_data {
	char name[32];
	u32 size;
D
Dan Williams 已提交
1019
	size_t addr;
1020 1021
};

1022
/* To debug any member of struct lbs_adapter, simply add one line here.
1023 1024 1025 1026 1027 1028 1029
 */
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)},
};

1030
static int num_of_items = ARRAY_SIZE(items);
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

/**
 *  @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
 */
1043
static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
			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 已提交
1066 1067
		else if (d[i].size == 8)
			val = *((u64 *) d[i].addr);
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

		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
 */
1087
static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
			    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;

1098
	pdata = kmalloc(cnt, GFP_KERNEL);
1099 1100 1101 1102
	if (pdata == NULL)
		return 0;

	if (copy_from_user(pdata, buf, cnt)) {
1103
		lbs_deb_debugfs("Copy from user failed\n");
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
		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++;
1122
			r = simple_strtoul(p2, NULL, 0);
1123 1124 1125 1126 1127 1128
			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 已提交
1129 1130
			else if (d[i].size == 8)
				*((u64 *) d[i].addr) = (u64) r;
1131 1132 1133 1134 1135
			break;
		} while (1);
	}
	kfree(pdata);

D
Dan Williams 已提交
1136
	return (ssize_t)cnt;
1137 1138
}

1139
static struct file_operations lbs_debug_fops = {
1140 1141
	.owner = THIS_MODULE,
	.open = open_file_generic,
1142 1143
	.write = lbs_debugfs_write,
	.read = lbs_debugfs_read,
1144 1145 1146 1147 1148
};

/**
 *  @brief create debug proc file
 *
1149
 *  @param priv	   pointer struct lbs_private
1150 1151 1152
 *  @param dev     pointer net_device
 *  @return 	   N/A
 */
1153
static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
1154 1155 1156 1157 1158 1159 1160
{
	int i;

	if (!priv->debugfs_dir)
		return;

	for (i = 0; i < num_of_items; i++)
D
Dan Williams 已提交
1161
		items[i].addr += (size_t) priv->adapter;
1162 1163 1164

	priv->debugfs_debug = debugfs_create_file("debug", 0644,
						  priv->debugfs_dir, &items[0],
1165
						  &lbs_debug_fops);
1166
}
1167
#endif