0001
0002 #include <linux/dcache.h>
0003 #include <linux/debugfs.h>
0004 #include <linux/delay.h>
0005 #include <linux/hardirq.h>
0006 #include <linux/mm.h>
0007 #include <linux/string.h>
0008 #include <linux/slab.h>
0009 #include <linux/export.h>
0010
0011 #include "decl.h"
0012 #include "cmd.h"
0013 #include "debugfs.h"
0014
0015 static struct dentry *lbs_dir;
0016 static char *szStates[] = {
0017 "Connected",
0018 "Disconnected"
0019 };
0020
0021 #ifdef PROC_DEBUG
0022 static void lbs_debug_init(struct lbs_private *priv);
0023 #endif
0024
0025 static ssize_t write_file_dummy(struct file *file, const char __user *buf,
0026 size_t count, loff_t *ppos)
0027 {
0028 return -EINVAL;
0029 }
0030
0031 static const size_t len = PAGE_SIZE;
0032
0033 static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
0034 size_t count, loff_t *ppos)
0035 {
0036 struct lbs_private *priv = file->private_data;
0037 size_t pos = 0;
0038 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0039 char *buf = (char *)addr;
0040 ssize_t res;
0041 if (!buf)
0042 return -ENOMEM;
0043
0044 pos += snprintf(buf+pos, len-pos, "state = %s\n",
0045 szStates[priv->connect_status]);
0046 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
0047 (u32) priv->regioncode);
0048
0049 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0050
0051 free_page(addr);
0052 return res;
0053 }
0054
0055 static ssize_t lbs_sleepparams_write(struct file *file,
0056 const char __user *user_buf, size_t count,
0057 loff_t *ppos)
0058 {
0059 struct lbs_private *priv = file->private_data;
0060 ssize_t ret;
0061 struct sleep_params sp;
0062 int p1, p2, p3, p4, p5, p6;
0063 char *buf;
0064
0065 buf = memdup_user_nul(user_buf, min(count, len - 1));
0066 if (IS_ERR(buf))
0067 return PTR_ERR(buf);
0068
0069 ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
0070 if (ret != 6) {
0071 ret = -EINVAL;
0072 goto out_unlock;
0073 }
0074 sp.sp_error = p1;
0075 sp.sp_offset = p2;
0076 sp.sp_stabletime = p3;
0077 sp.sp_calcontrol = p4;
0078 sp.sp_extsleepclk = p5;
0079 sp.sp_reserved = p6;
0080
0081 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
0082 if (!ret)
0083 ret = count;
0084 else if (ret > 0)
0085 ret = -EINVAL;
0086
0087 out_unlock:
0088 kfree(buf);
0089 return ret;
0090 }
0091
0092 static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
0093 size_t count, loff_t *ppos)
0094 {
0095 struct lbs_private *priv = file->private_data;
0096 ssize_t ret;
0097 size_t pos = 0;
0098 struct sleep_params sp;
0099 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0100 char *buf = (char *)addr;
0101 if (!buf)
0102 return -ENOMEM;
0103
0104 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
0105 if (ret)
0106 goto out_unlock;
0107
0108 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
0109 sp.sp_offset, sp.sp_stabletime,
0110 sp.sp_calcontrol, sp.sp_extsleepclk,
0111 sp.sp_reserved);
0112
0113 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0114
0115 out_unlock:
0116 free_page(addr);
0117 return ret;
0118 }
0119
0120 static ssize_t lbs_host_sleep_write(struct file *file,
0121 const char __user *user_buf, size_t count,
0122 loff_t *ppos)
0123 {
0124 struct lbs_private *priv = file->private_data;
0125 ssize_t ret;
0126 int host_sleep;
0127 char *buf;
0128
0129 buf = memdup_user_nul(user_buf, min(count, len - 1));
0130 if (IS_ERR(buf))
0131 return PTR_ERR(buf);
0132
0133 ret = sscanf(buf, "%d", &host_sleep);
0134 if (ret != 1) {
0135 ret = -EINVAL;
0136 goto out_unlock;
0137 }
0138
0139 if (host_sleep == 0)
0140 ret = lbs_set_host_sleep(priv, 0);
0141 else if (host_sleep == 1) {
0142 if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
0143 netdev_info(priv->dev,
0144 "wake parameters not configured\n");
0145 ret = -EINVAL;
0146 goto out_unlock;
0147 }
0148 ret = lbs_set_host_sleep(priv, 1);
0149 } else {
0150 netdev_err(priv->dev, "invalid option\n");
0151 ret = -EINVAL;
0152 }
0153
0154 if (!ret)
0155 ret = count;
0156
0157 out_unlock:
0158 kfree(buf);
0159 return ret;
0160 }
0161
0162 static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
0163 size_t count, loff_t *ppos)
0164 {
0165 struct lbs_private *priv = file->private_data;
0166 ssize_t ret;
0167 size_t pos = 0;
0168 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0169 char *buf = (char *)addr;
0170 if (!buf)
0171 return -ENOMEM;
0172
0173 pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
0174
0175 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0176
0177 free_page(addr);
0178 return ret;
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
0198 {
0199 struct mrvl_ie_header *tlv_h;
0200 uint16_t length;
0201 ssize_t pos = 0;
0202
0203 while (pos < size) {
0204 tlv_h = (struct mrvl_ie_header *) tlv;
0205 if (!tlv_h->len)
0206 return NULL;
0207 if (tlv_h->type == cpu_to_le16(tlv_type))
0208 return tlv_h;
0209 length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
0210 pos += length;
0211 tlv += length;
0212 }
0213 return NULL;
0214 }
0215
0216
0217 static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
0218 struct file *file, char __user *userbuf,
0219 size_t count, loff_t *ppos)
0220 {
0221 struct cmd_ds_802_11_subscribe_event *subscribed;
0222 struct mrvl_ie_thresholds *got;
0223 struct lbs_private *priv = file->private_data;
0224 ssize_t ret = 0;
0225 size_t pos = 0;
0226 char *buf;
0227 u8 value;
0228 u8 freq;
0229 int events = 0;
0230
0231 buf = (char *)get_zeroed_page(GFP_KERNEL);
0232 if (!buf)
0233 return -ENOMEM;
0234
0235 subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
0236 if (!subscribed) {
0237 ret = -ENOMEM;
0238 goto out_page;
0239 }
0240
0241 subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
0242 subscribed->action = cpu_to_le16(CMD_ACT_GET);
0243
0244 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
0245 if (ret)
0246 goto out_cmd;
0247
0248 got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
0249 if (got) {
0250 value = got->value;
0251 freq = got->freq;
0252 events = le16_to_cpu(subscribed->events);
0253
0254 pos += snprintf(buf, len, "%d %d %d\n", value, freq,
0255 !!(events & event_mask));
0256 }
0257
0258 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0259
0260 out_cmd:
0261 kfree(subscribed);
0262
0263 out_page:
0264 free_page((unsigned long)buf);
0265 return ret;
0266 }
0267
0268
0269 static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
0270 struct file *file,
0271 const char __user *userbuf, size_t count,
0272 loff_t *ppos)
0273 {
0274 struct cmd_ds_802_11_subscribe_event *events;
0275 struct mrvl_ie_thresholds *tlv;
0276 struct lbs_private *priv = file->private_data;
0277 int value, freq, new_mask;
0278 uint16_t curr_mask;
0279 char *buf;
0280 int ret;
0281
0282 buf = memdup_user_nul(userbuf, min(count, len - 1));
0283 if (IS_ERR(buf))
0284 return PTR_ERR(buf);
0285
0286 ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
0287 if (ret != 3) {
0288 ret = -EINVAL;
0289 goto out_page;
0290 }
0291 events = kzalloc(sizeof(*events), GFP_KERNEL);
0292 if (!events) {
0293 ret = -ENOMEM;
0294 goto out_page;
0295 }
0296
0297 events->hdr.size = cpu_to_le16(sizeof(*events));
0298 events->action = cpu_to_le16(CMD_ACT_GET);
0299
0300 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
0301 if (ret)
0302 goto out_events;
0303
0304 curr_mask = le16_to_cpu(events->events);
0305
0306 if (new_mask)
0307 new_mask = curr_mask | event_mask;
0308 else
0309 new_mask = curr_mask & ~event_mask;
0310
0311
0312
0313 tlv = (void *)events->tlv;
0314
0315 events->action = cpu_to_le16(CMD_ACT_SET);
0316 events->events = cpu_to_le16(new_mask);
0317 tlv->header.type = cpu_to_le16(tlv_type);
0318 tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
0319 tlv->value = value;
0320 if (tlv_type != TLV_TYPE_BCNMISS)
0321 tlv->freq = freq;
0322
0323
0324 events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
0325
0326 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
0327
0328 if (!ret)
0329 ret = count;
0330 out_events:
0331 kfree(events);
0332 out_page:
0333 kfree(buf);
0334 return ret;
0335 }
0336
0337
0338 static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
0339 size_t count, loff_t *ppos)
0340 {
0341 return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
0342 file, userbuf, count, ppos);
0343 }
0344
0345
0346 static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
0347 size_t count, loff_t *ppos)
0348 {
0349 return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
0350 file, userbuf, count, ppos);
0351 }
0352
0353
0354 static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
0355 size_t count, loff_t *ppos)
0356 {
0357 return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
0358 file, userbuf, count, ppos);
0359 }
0360
0361
0362 static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
0363 size_t count, loff_t *ppos)
0364 {
0365 return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
0366 file, userbuf, count, ppos);
0367 }
0368
0369
0370 static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
0371 size_t count, loff_t *ppos)
0372 {
0373 return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
0374 file, userbuf, count, ppos);
0375 }
0376
0377
0378 static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
0379 size_t count, loff_t *ppos)
0380 {
0381 return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
0382 file, userbuf, count, ppos);
0383 }
0384
0385
0386 static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
0387 size_t count, loff_t *ppos)
0388 {
0389 return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
0390 file, userbuf, count, ppos);
0391 }
0392
0393
0394 static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
0395 size_t count, loff_t *ppos)
0396 {
0397 return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
0398 file, userbuf, count, ppos);
0399 }
0400
0401
0402 static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
0403 size_t count, loff_t *ppos)
0404 {
0405 return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
0406 file, userbuf, count, ppos);
0407 }
0408
0409
0410 static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
0411 size_t count, loff_t *ppos)
0412 {
0413 return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
0414 file, userbuf, count, ppos);
0415 }
0416
0417 static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
0418 size_t count, loff_t *ppos)
0419 {
0420 return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
0421 file, userbuf, count, ppos);
0422 }
0423
0424
0425 static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
0426 size_t count, loff_t *ppos)
0427 {
0428 return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
0429 file, userbuf, count, ppos);
0430 }
0431
0432
0433 static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
0434 size_t count, loff_t *ppos)
0435 {
0436 struct lbs_private *priv = file->private_data;
0437 ssize_t pos = 0;
0438 int ret;
0439 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0440 char *buf = (char *)addr;
0441 u32 val = 0;
0442
0443 if (!buf)
0444 return -ENOMEM;
0445
0446 ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
0447 mdelay(10);
0448 if (!ret) {
0449 pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
0450 priv->mac_offset, val);
0451 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0452 }
0453 free_page(addr);
0454 return ret;
0455 }
0456
0457 static ssize_t lbs_rdmac_write(struct file *file,
0458 const char __user *userbuf,
0459 size_t count, loff_t *ppos)
0460 {
0461 struct lbs_private *priv = file->private_data;
0462 char *buf;
0463
0464 buf = memdup_user_nul(userbuf, min(count, len - 1));
0465 if (IS_ERR(buf))
0466 return PTR_ERR(buf);
0467
0468 priv->mac_offset = simple_strtoul(buf, NULL, 16);
0469 kfree(buf);
0470 return count;
0471 }
0472
0473 static ssize_t lbs_wrmac_write(struct file *file,
0474 const char __user *userbuf,
0475 size_t count, loff_t *ppos)
0476 {
0477
0478 struct lbs_private *priv = file->private_data;
0479 ssize_t res;
0480 u32 offset, value;
0481 char *buf;
0482
0483 buf = memdup_user_nul(userbuf, min(count, len - 1));
0484 if (IS_ERR(buf))
0485 return PTR_ERR(buf);
0486
0487 res = sscanf(buf, "%x %x", &offset, &value);
0488 if (res != 2) {
0489 res = -EFAULT;
0490 goto out_unlock;
0491 }
0492
0493 res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
0494 mdelay(10);
0495
0496 if (!res)
0497 res = count;
0498 out_unlock:
0499 kfree(buf);
0500 return res;
0501 }
0502
0503 static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
0504 size_t count, loff_t *ppos)
0505 {
0506 struct lbs_private *priv = file->private_data;
0507 ssize_t pos = 0;
0508 int ret;
0509 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0510 char *buf = (char *)addr;
0511 u32 val;
0512
0513 if (!buf)
0514 return -ENOMEM;
0515
0516 ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
0517 mdelay(10);
0518 if (!ret) {
0519 pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
0520 priv->bbp_offset, val);
0521 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0522 }
0523 free_page(addr);
0524
0525 return ret;
0526 }
0527
0528 static ssize_t lbs_rdbbp_write(struct file *file,
0529 const char __user *userbuf,
0530 size_t count, loff_t *ppos)
0531 {
0532 struct lbs_private *priv = file->private_data;
0533 char *buf;
0534
0535 buf = memdup_user_nul(userbuf, min(count, len - 1));
0536 if (IS_ERR(buf))
0537 return PTR_ERR(buf);
0538
0539 priv->bbp_offset = simple_strtoul(buf, NULL, 16);
0540 kfree(buf);
0541
0542 return count;
0543 }
0544
0545 static ssize_t lbs_wrbbp_write(struct file *file,
0546 const char __user *userbuf,
0547 size_t count, loff_t *ppos)
0548 {
0549
0550 struct lbs_private *priv = file->private_data;
0551 ssize_t res;
0552 u32 offset, value;
0553 char *buf;
0554
0555 buf = memdup_user_nul(userbuf, min(count, len - 1));
0556 if (IS_ERR(buf))
0557 return PTR_ERR(buf);
0558
0559 res = sscanf(buf, "%x %x", &offset, &value);
0560 if (res != 2) {
0561 res = -EFAULT;
0562 goto out_unlock;
0563 }
0564
0565 res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
0566 mdelay(10);
0567
0568 if (!res)
0569 res = count;
0570 out_unlock:
0571 kfree(buf);
0572 return res;
0573 }
0574
0575 static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
0576 size_t count, loff_t *ppos)
0577 {
0578 struct lbs_private *priv = file->private_data;
0579 ssize_t pos = 0;
0580 int ret;
0581 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0582 char *buf = (char *)addr;
0583 u32 val;
0584
0585 if (!buf)
0586 return -ENOMEM;
0587
0588 ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
0589 mdelay(10);
0590 if (!ret) {
0591 pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
0592 priv->rf_offset, val);
0593 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
0594 }
0595 free_page(addr);
0596
0597 return ret;
0598 }
0599
0600 static ssize_t lbs_rdrf_write(struct file *file,
0601 const char __user *userbuf,
0602 size_t count, loff_t *ppos)
0603 {
0604 struct lbs_private *priv = file->private_data;
0605 char *buf;
0606
0607 buf = memdup_user_nul(userbuf, min(count, len - 1));
0608 if (IS_ERR(buf))
0609 return PTR_ERR(buf);
0610
0611 priv->rf_offset = simple_strtoul(buf, NULL, 16);
0612 kfree(buf);
0613 return count;
0614 }
0615
0616 static ssize_t lbs_wrrf_write(struct file *file,
0617 const char __user *userbuf,
0618 size_t count, loff_t *ppos)
0619 {
0620
0621 struct lbs_private *priv = file->private_data;
0622 ssize_t res;
0623 u32 offset, value;
0624 char *buf;
0625
0626 buf = memdup_user_nul(userbuf, min(count, len - 1));
0627 if (IS_ERR(buf))
0628 return PTR_ERR(buf);
0629
0630 res = sscanf(buf, "%x %x", &offset, &value);
0631 if (res != 2) {
0632 res = -EFAULT;
0633 goto out_unlock;
0634 }
0635
0636 res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
0637 mdelay(10);
0638
0639 if (!res)
0640 res = count;
0641 out_unlock:
0642 kfree(buf);
0643 return res;
0644 }
0645
0646 #define FOPS(fread, fwrite) { \
0647 .owner = THIS_MODULE, \
0648 .open = simple_open, \
0649 .read = (fread), \
0650 .write = (fwrite), \
0651 .llseek = generic_file_llseek, \
0652 }
0653
0654 struct lbs_debugfs_files {
0655 const char *name;
0656 umode_t perm;
0657 struct file_operations fops;
0658 };
0659
0660 static const struct lbs_debugfs_files debugfs_files[] = {
0661 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
0662 { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
0663 lbs_sleepparams_write), },
0664 { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
0665 lbs_host_sleep_write), },
0666 };
0667
0668 static const struct lbs_debugfs_files debugfs_events_files[] = {
0669 {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
0670 lbs_lowrssi_write), },
0671 {"low_snr", 0644, FOPS(lbs_lowsnr_read,
0672 lbs_lowsnr_write), },
0673 {"failure_count", 0644, FOPS(lbs_failcount_read,
0674 lbs_failcount_write), },
0675 {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
0676 lbs_bcnmiss_write), },
0677 {"high_rssi", 0644, FOPS(lbs_highrssi_read,
0678 lbs_highrssi_write), },
0679 {"high_snr", 0644, FOPS(lbs_highsnr_read,
0680 lbs_highsnr_write), },
0681 };
0682
0683 static const struct lbs_debugfs_files debugfs_regs_files[] = {
0684 {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
0685 {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
0686 {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
0687 {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
0688 {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
0689 {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
0690 };
0691
0692 void lbs_debugfs_init(void)
0693 {
0694 if (!lbs_dir)
0695 lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
0696 }
0697
0698 void lbs_debugfs_remove(void)
0699 {
0700 debugfs_remove(lbs_dir);
0701 }
0702
0703 void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
0704 {
0705 int i;
0706 const struct lbs_debugfs_files *files;
0707 if (!lbs_dir)
0708 goto exit;
0709
0710 priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
0711
0712 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
0713 files = &debugfs_files[i];
0714 priv->debugfs_files[i] = debugfs_create_file(files->name,
0715 files->perm,
0716 priv->debugfs_dir,
0717 priv,
0718 &files->fops);
0719 }
0720
0721 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
0722
0723 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
0724 files = &debugfs_events_files[i];
0725 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
0726 files->perm,
0727 priv->events_dir,
0728 priv,
0729 &files->fops);
0730 }
0731
0732 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
0733
0734 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
0735 files = &debugfs_regs_files[i];
0736 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
0737 files->perm,
0738 priv->regs_dir,
0739 priv,
0740 &files->fops);
0741 }
0742
0743 #ifdef PROC_DEBUG
0744 lbs_debug_init(priv);
0745 #endif
0746 exit:
0747 return;
0748 }
0749
0750 void lbs_debugfs_remove_one(struct lbs_private *priv)
0751 {
0752 int i;
0753
0754 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
0755 debugfs_remove(priv->debugfs_regs_files[i]);
0756
0757 debugfs_remove(priv->regs_dir);
0758
0759 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
0760 debugfs_remove(priv->debugfs_events_files[i]);
0761
0762 debugfs_remove(priv->events_dir);
0763 #ifdef PROC_DEBUG
0764 debugfs_remove(priv->debugfs_debug);
0765 #endif
0766 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
0767 debugfs_remove(priv->debugfs_files[i]);
0768 debugfs_remove(priv->debugfs_dir);
0769 }
0770
0771
0772
0773
0774
0775 #ifdef PROC_DEBUG
0776
0777 #define item_size(n) (sizeof_field(struct lbs_private, n))
0778 #define item_addr(n) (offsetof(struct lbs_private, n))
0779
0780
0781 struct debug_data {
0782 char name[32];
0783 u32 size;
0784 size_t addr;
0785 };
0786
0787
0788
0789 static struct debug_data items[] = {
0790 {"psmode", item_size(psmode), item_addr(psmode)},
0791 {"psstate", item_size(psstate), item_addr(psstate)},
0792 };
0793
0794 static int num_of_items = ARRAY_SIZE(items);
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806 static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
0807 size_t count, loff_t *ppos)
0808 {
0809 int val = 0;
0810 size_t pos = 0;
0811 ssize_t res;
0812 char *p;
0813 int i;
0814 struct debug_data *d;
0815 unsigned long addr = get_zeroed_page(GFP_KERNEL);
0816 char *buf = (char *)addr;
0817 if (!buf)
0818 return -ENOMEM;
0819
0820 p = buf;
0821
0822 d = file->private_data;
0823
0824 for (i = 0; i < num_of_items; i++) {
0825 if (d[i].size == 1)
0826 val = *((u8 *) d[i].addr);
0827 else if (d[i].size == 2)
0828 val = *((u16 *) d[i].addr);
0829 else if (d[i].size == 4)
0830 val = *((u32 *) d[i].addr);
0831 else if (d[i].size == 8)
0832 val = *((u64 *) d[i].addr);
0833
0834 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
0835 }
0836
0837 res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
0838
0839 free_page(addr);
0840 return res;
0841 }
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853 static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
0854 size_t cnt, loff_t *ppos)
0855 {
0856 int r, i;
0857 char *pdata;
0858 char *p;
0859 char *p0;
0860 char *p1;
0861 char *p2;
0862 struct debug_data *d = f->private_data;
0863
0864 if (cnt == 0)
0865 return 0;
0866
0867 pdata = memdup_user_nul(buf, cnt);
0868 if (IS_ERR(pdata))
0869 return PTR_ERR(pdata);
0870
0871 p0 = pdata;
0872 for (i = 0; i < num_of_items; i++) {
0873 do {
0874 p = strstr(p0, d[i].name);
0875 if (p == NULL)
0876 break;
0877 p1 = strchr(p, '\n');
0878 if (p1 == NULL)
0879 break;
0880 p0 = p1++;
0881 p2 = strchr(p, '=');
0882 if (!p2)
0883 break;
0884 p2++;
0885 r = simple_strtoul(p2, NULL, 0);
0886 if (d[i].size == 1)
0887 *((u8 *) d[i].addr) = (u8) r;
0888 else if (d[i].size == 2)
0889 *((u16 *) d[i].addr) = (u16) r;
0890 else if (d[i].size == 4)
0891 *((u32 *) d[i].addr) = (u32) r;
0892 else if (d[i].size == 8)
0893 *((u64 *) d[i].addr) = (u64) r;
0894 break;
0895 } while (1);
0896 }
0897 kfree(pdata);
0898
0899 return (ssize_t)cnt;
0900 }
0901
0902 static const struct file_operations lbs_debug_fops = {
0903 .owner = THIS_MODULE,
0904 .open = simple_open,
0905 .write = lbs_debugfs_write,
0906 .read = lbs_debugfs_read,
0907 .llseek = default_llseek,
0908 };
0909
0910
0911
0912
0913
0914
0915
0916
0917 static void lbs_debug_init(struct lbs_private *priv)
0918 {
0919 int i;
0920
0921 if (!priv->debugfs_dir)
0922 return;
0923
0924 for (i = 0; i < num_of_items; i++)
0925 items[i].addr += (size_t) priv;
0926
0927 priv->debugfs_debug = debugfs_create_file("debug", 0644,
0928 priv->debugfs_dir, &items[0],
0929 &lbs_debug_fops);
0930 }
0931 #endif