Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
0183  * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
0184  * firmware. Here's an example:
0185  *  04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
0186  *  00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
0187  *  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0188  *
0189  * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
0190  * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
0191  * defined in mrvlietypes_thresholds
0192  *
0193  * This function searches in this TLV data chunk for a given TLV type
0194  * and returns a pointer to the first data byte of the TLV, or to NULL
0195  * if the TLV hasn't been found.
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     /* Now everything is set and we can send stuff down to the firmware */
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     /* The command header, the action, the event mask, and one TLV */
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 /* debug entry */
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 /* To debug any member of struct lbs_private, simply add one line here.
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  * lbs_debugfs_read - proc read function
0798  *
0799  * @file:   file to read
0800  * @userbuf:    pointer to buffer
0801  * @count:  number of bytes to read
0802  * @ppos:   read data starting position
0803  *
0804  * returns: amount of data read or negative error code
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  * lbs_debugfs_write - proc write function
0845  *
0846  * @f:      file pointer
0847  * @buf:    pointer to data buffer
0848  * @cnt:    data number to write
0849  * @ppos:   file position
0850  *
0851  * returns: amount of data written
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  * lbs_debug_init - create debug proc file
0912  *
0913  * @priv:   pointer to &struct lbs_private
0914  *
0915  * returns: N/A
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