debugfs.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * NXP Wireless LAN device driver: debugfs
  4. *
  5. * Copyright 2011-2020 NXP
  6. */
  7. #include <linux/debugfs.h>
  8. #include "main.h"
  9. #include "11n.h"
  10. static struct dentry *mwifiex_dfs_dir;
  11. static char *bss_modes[] = {
  12. "UNSPECIFIED",
  13. "ADHOC",
  14. "STATION",
  15. "AP",
  16. "AP_VLAN",
  17. "WDS",
  18. "MONITOR",
  19. "MESH_POINT",
  20. "P2P_CLIENT",
  21. "P2P_GO",
  22. "P2P_DEVICE",
  23. };
  24. /*
  25. * Proc info file read handler.
  26. *
  27. * This function is called when the 'info' file is opened for reading.
  28. * It prints the following driver related information -
  29. * - Driver name
  30. * - Driver version
  31. * - Driver extended version
  32. * - Interface name
  33. * - BSS mode
  34. * - Media state (connected or disconnected)
  35. * - MAC address
  36. * - Total number of Tx bytes
  37. * - Total number of Rx bytes
  38. * - Total number of Tx packets
  39. * - Total number of Rx packets
  40. * - Total number of dropped Tx packets
  41. * - Total number of dropped Rx packets
  42. * - Total number of corrupted Tx packets
  43. * - Total number of corrupted Rx packets
  44. * - Carrier status (on or off)
  45. * - Tx queue status (started or stopped)
  46. *
  47. * For STA mode drivers, it also prints the following extra -
  48. * - ESSID
  49. * - BSSID
  50. * - Channel
  51. * - Region code
  52. * - Multicast count
  53. * - Multicast addresses
  54. */
  55. static ssize_t
  56. mwifiex_info_read(struct file *file, char __user *ubuf,
  57. size_t count, loff_t *ppos)
  58. {
  59. struct mwifiex_private *priv =
  60. (struct mwifiex_private *) file->private_data;
  61. struct net_device *netdev = priv->netdev;
  62. struct netdev_hw_addr *ha;
  63. struct netdev_queue *txq;
  64. unsigned long page = get_zeroed_page(GFP_KERNEL);
  65. char *p = (char *) page, fmt[64];
  66. struct mwifiex_bss_info info;
  67. ssize_t ret;
  68. int i = 0;
  69. if (!p)
  70. return -ENOMEM;
  71. memset(&info, 0, sizeof(info));
  72. ret = mwifiex_get_bss_info(priv, &info);
  73. if (ret)
  74. goto free_and_exit;
  75. mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
  76. mwifiex_get_ver_ext(priv, 0);
  77. p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
  78. p += sprintf(p, "driver_version = %s", fmt);
  79. p += sprintf(p, "\nverext = %s", priv->version_str);
  80. p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
  81. if (info.bss_mode >= ARRAY_SIZE(bss_modes))
  82. p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
  83. else
  84. p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
  85. p += sprintf(p, "media_state=\"%s\"\n",
  86. (!priv->media_connected ? "Disconnected" : "Connected"));
  87. p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
  88. if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
  89. p += sprintf(p, "multicast_count=\"%d\"\n",
  90. netdev_mc_count(netdev));
  91. p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
  92. info.ssid.ssid);
  93. p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
  94. p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
  95. p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
  96. p += sprintf(p, "region_code=\"0x%x\"\n",
  97. priv->adapter->region_code);
  98. netdev_for_each_mc_addr(ha, netdev)
  99. p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
  100. i++, ha->addr);
  101. }
  102. p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
  103. p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
  104. p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
  105. p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
  106. p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
  107. p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
  108. p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
  109. p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
  110. p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
  111. ? "on" : "off"));
  112. p += sprintf(p, "tx queue");
  113. for (i = 0; i < netdev->num_tx_queues; i++) {
  114. txq = netdev_get_tx_queue(netdev, i);
  115. p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
  116. "stopped" : "started");
  117. }
  118. p += sprintf(p, "\n");
  119. ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
  120. (unsigned long) p - page);
  121. free_and_exit:
  122. free_page(page);
  123. return ret;
  124. }
  125. /*
  126. * Proc getlog file read handler.
  127. *
  128. * This function is called when the 'getlog' file is opened for reading
  129. * It prints the following log information -
  130. * - Number of multicast Tx frames
  131. * - Number of failed packets
  132. * - Number of Tx retries
  133. * - Number of multicast Tx retries
  134. * - Number of duplicate frames
  135. * - Number of RTS successes
  136. * - Number of RTS failures
  137. * - Number of ACK failures
  138. * - Number of fragmented Rx frames
  139. * - Number of multicast Rx frames
  140. * - Number of FCS errors
  141. * - Number of Tx frames
  142. * - WEP ICV error counts
  143. * - Number of received beacons
  144. * - Number of missed beacons
  145. */
  146. static ssize_t
  147. mwifiex_getlog_read(struct file *file, char __user *ubuf,
  148. size_t count, loff_t *ppos)
  149. {
  150. struct mwifiex_private *priv =
  151. (struct mwifiex_private *) file->private_data;
  152. unsigned long page = get_zeroed_page(GFP_KERNEL);
  153. char *p = (char *) page;
  154. ssize_t ret;
  155. struct mwifiex_ds_get_stats stats;
  156. if (!p)
  157. return -ENOMEM;
  158. memset(&stats, 0, sizeof(stats));
  159. ret = mwifiex_get_stats_info(priv, &stats);
  160. if (ret)
  161. goto free_and_exit;
  162. p += sprintf(p, "\n"
  163. "mcasttxframe %u\n"
  164. "failed %u\n"
  165. "retry %u\n"
  166. "multiretry %u\n"
  167. "framedup %u\n"
  168. "rtssuccess %u\n"
  169. "rtsfailure %u\n"
  170. "ackfailure %u\n"
  171. "rxfrag %u\n"
  172. "mcastrxframe %u\n"
  173. "fcserror %u\n"
  174. "txframe %u\n"
  175. "wepicverrcnt-1 %u\n"
  176. "wepicverrcnt-2 %u\n"
  177. "wepicverrcnt-3 %u\n"
  178. "wepicverrcnt-4 %u\n"
  179. "bcn_rcv_cnt %u\n"
  180. "bcn_miss_cnt %u\n",
  181. stats.mcast_tx_frame,
  182. stats.failed,
  183. stats.retry,
  184. stats.multi_retry,
  185. stats.frame_dup,
  186. stats.rts_success,
  187. stats.rts_failure,
  188. stats.ack_failure,
  189. stats.rx_frag,
  190. stats.mcast_rx_frame,
  191. stats.fcs_error,
  192. stats.tx_frame,
  193. stats.wep_icv_error[0],
  194. stats.wep_icv_error[1],
  195. stats.wep_icv_error[2],
  196. stats.wep_icv_error[3],
  197. stats.bcn_rcv_cnt,
  198. stats.bcn_miss_cnt);
  199. ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
  200. (unsigned long) p - page);
  201. free_and_exit:
  202. free_page(page);
  203. return ret;
  204. }
  205. /* Sysfs histogram file read handler.
  206. *
  207. * This function is called when the 'histogram' file is opened for reading
  208. * It prints the following histogram information -
  209. * - Number of histogram samples
  210. * - Receive packet number of each rx_rate
  211. * - Receive packet number of each snr
  212. * - Receive packet number of each nosie_flr
  213. * - Receive packet number of each signal streath
  214. */
  215. static ssize_t
  216. mwifiex_histogram_read(struct file *file, char __user *ubuf,
  217. size_t count, loff_t *ppos)
  218. {
  219. struct mwifiex_private *priv =
  220. (struct mwifiex_private *)file->private_data;
  221. ssize_t ret;
  222. struct mwifiex_histogram_data *phist_data;
  223. int i, value;
  224. unsigned long page = get_zeroed_page(GFP_KERNEL);
  225. char *p = (char *)page;
  226. if (!p)
  227. return -ENOMEM;
  228. if (!priv || !priv->hist_data) {
  229. ret = -EFAULT;
  230. goto free_and_exit;
  231. }
  232. phist_data = priv->hist_data;
  233. p += sprintf(p, "\n"
  234. "total samples = %d\n",
  235. atomic_read(&phist_data->num_samples));
  236. p += sprintf(p,
  237. "rx rates (in Mbps): 0=1M 1=2M 2=5.5M 3=11M 4=6M 5=9M 6=12M\n"
  238. "7=18M 8=24M 9=36M 10=48M 11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
  239. if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
  240. p += sprintf(p,
  241. "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");
  242. } else {
  243. p += sprintf(p, "\n");
  244. }
  245. for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {
  246. value = atomic_read(&phist_data->rx_rate[i]);
  247. if (value)
  248. p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
  249. }
  250. if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
  251. for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;
  252. i++) {
  253. value = atomic_read(&phist_data->rx_rate[i]);
  254. if (value)
  255. p += sprintf(p, "rx_rate[%02d] = %d\n",
  256. i, value);
  257. }
  258. }
  259. for (i = 0; i < MWIFIEX_MAX_SNR; i++) {
  260. value = atomic_read(&phist_data->snr[i]);
  261. if (value)
  262. p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
  263. }
  264. for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
  265. value = atomic_read(&phist_data->noise_flr[i]);
  266. if (value)
  267. p += sprintf(p, "noise_flr[%02ddBm] = %d\n",
  268. (int)(i-128), value);
  269. }
  270. for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
  271. value = atomic_read(&phist_data->sig_str[i]);
  272. if (value)
  273. p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
  274. i, value);
  275. }
  276. ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
  277. (unsigned long)p - page);
  278. free_and_exit:
  279. free_page(page);
  280. return ret;
  281. }
  282. static ssize_t
  283. mwifiex_histogram_write(struct file *file, const char __user *ubuf,
  284. size_t count, loff_t *ppos)
  285. {
  286. struct mwifiex_private *priv = (void *)file->private_data;
  287. if (priv && priv->hist_data)
  288. mwifiex_hist_data_reset(priv);
  289. return 0;
  290. }
  291. static struct mwifiex_debug_info info;
  292. /*
  293. * Proc debug file read handler.
  294. *
  295. * This function is called when the 'debug' file is opened for reading
  296. * It prints the following log information -
  297. * - Interrupt count
  298. * - WMM AC VO packets count
  299. * - WMM AC VI packets count
  300. * - WMM AC BE packets count
  301. * - WMM AC BK packets count
  302. * - Maximum Tx buffer size
  303. * - Tx buffer size
  304. * - Current Tx buffer size
  305. * - Power Save mode
  306. * - Power Save state
  307. * - Deep Sleep status
  308. * - Device wakeup required status
  309. * - Number of wakeup tries
  310. * - Host Sleep configured status
  311. * - Host Sleep activated status
  312. * - Number of Tx timeouts
  313. * - Number of command timeouts
  314. * - Last timed out command ID
  315. * - Last timed out command action
  316. * - Last command ID
  317. * - Last command action
  318. * - Last command index
  319. * - Last command response ID
  320. * - Last command response index
  321. * - Last event
  322. * - Last event index
  323. * - Number of host to card command failures
  324. * - Number of sleep confirm command failures
  325. * - Number of host to card data failure
  326. * - Number of deauthentication events
  327. * - Number of disassociation events
  328. * - Number of link lost events
  329. * - Number of deauthentication commands
  330. * - Number of association success commands
  331. * - Number of association failure commands
  332. * - Number of commands sent
  333. * - Number of data packets sent
  334. * - Number of command responses received
  335. * - Number of events received
  336. * - Tx BA stream table (TID, RA)
  337. * - Rx reorder table (TID, TA, Start window, Window size, Buffer)
  338. */
  339. static ssize_t
  340. mwifiex_debug_read(struct file *file, char __user *ubuf,
  341. size_t count, loff_t *ppos)
  342. {
  343. struct mwifiex_private *priv =
  344. (struct mwifiex_private *) file->private_data;
  345. unsigned long page = get_zeroed_page(GFP_KERNEL);
  346. char *p = (char *) page;
  347. ssize_t ret;
  348. if (!p)
  349. return -ENOMEM;
  350. ret = mwifiex_get_debug_info(priv, &info);
  351. if (ret)
  352. goto free_and_exit;
  353. p += mwifiex_debug_info_to_buffer(priv, p, &info);
  354. ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
  355. (unsigned long) p - page);
  356. free_and_exit:
  357. free_page(page);
  358. return ret;
  359. }
  360. static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
  361. /*
  362. * Proc regrdwr file write handler.
  363. *
  364. * This function is called when the 'regrdwr' file is opened for writing
  365. *
  366. * This function can be used to write to a register.
  367. */
  368. static ssize_t
  369. mwifiex_regrdwr_write(struct file *file,
  370. const char __user *ubuf, size_t count, loff_t *ppos)
  371. {
  372. char *buf;
  373. int ret;
  374. u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
  375. buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
  376. if (IS_ERR(buf))
  377. return PTR_ERR(buf);
  378. sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
  379. if (reg_type == 0 || reg_offset == 0) {
  380. ret = -EINVAL;
  381. goto done;
  382. } else {
  383. saved_reg_type = reg_type;
  384. saved_reg_offset = reg_offset;
  385. saved_reg_value = reg_value;
  386. ret = count;
  387. }
  388. done:
  389. kfree(buf);
  390. return ret;
  391. }
  392. /*
  393. * Proc regrdwr file read handler.
  394. *
  395. * This function is called when the 'regrdwr' file is opened for reading
  396. *
  397. * This function can be used to read from a register.
  398. */
  399. static ssize_t
  400. mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
  401. size_t count, loff_t *ppos)
  402. {
  403. struct mwifiex_private *priv =
  404. (struct mwifiex_private *) file->private_data;
  405. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  406. char *buf = (char *) addr;
  407. int pos = 0, ret = 0;
  408. u32 reg_value;
  409. if (!buf)
  410. return -ENOMEM;
  411. if (!saved_reg_type) {
  412. /* No command has been given */
  413. pos += snprintf(buf, PAGE_SIZE, "0");
  414. goto done;
  415. }
  416. /* Set command has been given */
  417. if (saved_reg_value != UINT_MAX) {
  418. ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
  419. saved_reg_value);
  420. pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
  421. saved_reg_type, saved_reg_offset,
  422. saved_reg_value);
  423. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  424. goto done;
  425. }
  426. /* Get command has been given */
  427. ret = mwifiex_reg_read(priv, saved_reg_type,
  428. saved_reg_offset, &reg_value);
  429. if (ret) {
  430. ret = -EINVAL;
  431. goto done;
  432. }
  433. pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
  434. saved_reg_offset, reg_value);
  435. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  436. done:
  437. free_page(addr);
  438. return ret;
  439. }
  440. /* Proc debug_mask file read handler.
  441. * This function is called when the 'debug_mask' file is opened for reading
  442. * This function can be used read driver debugging mask value.
  443. */
  444. static ssize_t
  445. mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
  446. size_t count, loff_t *ppos)
  447. {
  448. struct mwifiex_private *priv =
  449. (struct mwifiex_private *)file->private_data;
  450. unsigned long page = get_zeroed_page(GFP_KERNEL);
  451. char *buf = (char *)page;
  452. size_t ret = 0;
  453. int pos = 0;
  454. if (!buf)
  455. return -ENOMEM;
  456. pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
  457. priv->adapter->debug_mask);
  458. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  459. free_page(page);
  460. return ret;
  461. }
  462. /* Proc debug_mask file read handler.
  463. * This function is called when the 'debug_mask' file is opened for reading
  464. * This function can be used read driver debugging mask value.
  465. */
  466. static ssize_t
  467. mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
  468. size_t count, loff_t *ppos)
  469. {
  470. int ret;
  471. unsigned long debug_mask;
  472. struct mwifiex_private *priv = (void *)file->private_data;
  473. char *buf;
  474. buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
  475. if (IS_ERR(buf))
  476. return PTR_ERR(buf);
  477. if (kstrtoul(buf, 0, &debug_mask)) {
  478. ret = -EINVAL;
  479. goto done;
  480. }
  481. priv->adapter->debug_mask = debug_mask;
  482. ret = count;
  483. done:
  484. kfree(buf);
  485. return ret;
  486. }
  487. /* debugfs verext file write handler.
  488. * This function is called when the 'verext' file is opened for write
  489. */
  490. static ssize_t
  491. mwifiex_verext_write(struct file *file, const char __user *ubuf,
  492. size_t count, loff_t *ppos)
  493. {
  494. int ret;
  495. u32 versionstrsel;
  496. struct mwifiex_private *priv = (void *)file->private_data;
  497. char buf[16];
  498. memset(buf, 0, sizeof(buf));
  499. if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
  500. return -EFAULT;
  501. ret = kstrtou32(buf, 10, &versionstrsel);
  502. if (ret)
  503. return ret;
  504. priv->versionstrsel = versionstrsel;
  505. return count;
  506. }
  507. /* Proc verext file read handler.
  508. * This function is called when the 'verext' file is opened for reading
  509. * This function can be used read driver exteneed verion string.
  510. */
  511. static ssize_t
  512. mwifiex_verext_read(struct file *file, char __user *ubuf,
  513. size_t count, loff_t *ppos)
  514. {
  515. struct mwifiex_private *priv =
  516. (struct mwifiex_private *)file->private_data;
  517. char buf[256];
  518. int ret;
  519. mwifiex_get_ver_ext(priv, priv->versionstrsel);
  520. ret = snprintf(buf, sizeof(buf), "version string: %s\n",
  521. priv->version_str);
  522. return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
  523. }
  524. /* Proc memrw file write handler.
  525. * This function is called when the 'memrw' file is opened for writing
  526. * This function can be used to write to a memory location.
  527. */
  528. static ssize_t
  529. mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
  530. loff_t *ppos)
  531. {
  532. int ret;
  533. char cmd;
  534. struct mwifiex_ds_mem_rw mem_rw;
  535. u16 cmd_action;
  536. struct mwifiex_private *priv = (void *)file->private_data;
  537. char *buf;
  538. buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
  539. if (IS_ERR(buf))
  540. return PTR_ERR(buf);
  541. ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
  542. if (ret != 3) {
  543. ret = -EINVAL;
  544. goto done;
  545. }
  546. if ((cmd == 'r') || (cmd == 'R')) {
  547. cmd_action = HostCmd_ACT_GEN_GET;
  548. mem_rw.value = 0;
  549. } else if ((cmd == 'w') || (cmd == 'W')) {
  550. cmd_action = HostCmd_ACT_GEN_SET;
  551. } else {
  552. ret = -EINVAL;
  553. goto done;
  554. }
  555. memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
  556. if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
  557. &mem_rw, true))
  558. ret = -1;
  559. else
  560. ret = count;
  561. done:
  562. kfree(buf);
  563. return ret;
  564. }
  565. /* Proc memrw file read handler.
  566. * This function is called when the 'memrw' file is opened for reading
  567. * This function can be used to read from a memory location.
  568. */
  569. static ssize_t
  570. mwifiex_memrw_read(struct file *file, char __user *ubuf,
  571. size_t count, loff_t *ppos)
  572. {
  573. struct mwifiex_private *priv = (void *)file->private_data;
  574. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  575. char *buf = (char *)addr;
  576. int ret, pos = 0;
  577. if (!buf)
  578. return -ENOMEM;
  579. pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
  580. priv->mem_rw.value);
  581. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  582. free_page(addr);
  583. return ret;
  584. }
  585. static u32 saved_offset = -1, saved_bytes = -1;
  586. /*
  587. * Proc rdeeprom file write handler.
  588. *
  589. * This function is called when the 'rdeeprom' file is opened for writing
  590. *
  591. * This function can be used to write to a RDEEPROM location.
  592. */
  593. static ssize_t
  594. mwifiex_rdeeprom_write(struct file *file,
  595. const char __user *ubuf, size_t count, loff_t *ppos)
  596. {
  597. char *buf;
  598. int ret = 0;
  599. int offset = -1, bytes = -1;
  600. buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
  601. if (IS_ERR(buf))
  602. return PTR_ERR(buf);
  603. sscanf(buf, "%d %d", &offset, &bytes);
  604. if (offset == -1 || bytes == -1) {
  605. ret = -EINVAL;
  606. goto done;
  607. } else {
  608. saved_offset = offset;
  609. saved_bytes = bytes;
  610. ret = count;
  611. }
  612. done:
  613. kfree(buf);
  614. return ret;
  615. }
  616. /*
  617. * Proc rdeeprom read write handler.
  618. *
  619. * This function is called when the 'rdeeprom' file is opened for reading
  620. *
  621. * This function can be used to read from a RDEEPROM location.
  622. */
  623. static ssize_t
  624. mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
  625. size_t count, loff_t *ppos)
  626. {
  627. struct mwifiex_private *priv =
  628. (struct mwifiex_private *) file->private_data;
  629. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  630. char *buf = (char *) addr;
  631. int pos, ret, i;
  632. u8 value[MAX_EEPROM_DATA];
  633. if (!buf)
  634. return -ENOMEM;
  635. if (saved_offset == -1) {
  636. /* No command has been given */
  637. pos = snprintf(buf, PAGE_SIZE, "0");
  638. goto done;
  639. }
  640. /* Get command has been given */
  641. ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
  642. (u16) saved_bytes, value);
  643. if (ret) {
  644. ret = -EINVAL;
  645. goto out_free;
  646. }
  647. pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
  648. for (i = 0; i < saved_bytes; i++)
  649. pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
  650. done:
  651. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  652. out_free:
  653. free_page(addr);
  654. return ret;
  655. }
  656. /* Proc hscfg file write handler
  657. * This function can be used to configure the host sleep parameters.
  658. */
  659. static ssize_t
  660. mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
  661. size_t count, loff_t *ppos)
  662. {
  663. struct mwifiex_private *priv = (void *)file->private_data;
  664. char *buf;
  665. int ret, arg_num;
  666. struct mwifiex_ds_hs_cfg hscfg;
  667. int conditions = HS_CFG_COND_DEF;
  668. u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
  669. buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
  670. if (IS_ERR(buf))
  671. return PTR_ERR(buf);
  672. arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
  673. memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
  674. if (arg_num > 3) {
  675. mwifiex_dbg(priv->adapter, ERROR,
  676. "Too many arguments\n");
  677. ret = -EINVAL;
  678. goto done;
  679. }
  680. if (arg_num >= 1 && arg_num < 3)
  681. mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
  682. MWIFIEX_SYNC_CMD, &hscfg);
  683. if (arg_num) {
  684. if (conditions == HS_CFG_CANCEL) {
  685. mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);
  686. ret = count;
  687. goto done;
  688. }
  689. hscfg.conditions = conditions;
  690. }
  691. if (arg_num >= 2)
  692. hscfg.gpio = gpio;
  693. if (arg_num == 3)
  694. hscfg.gap = gap;
  695. hscfg.is_invoke_hostcmd = false;
  696. mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
  697. MWIFIEX_SYNC_CMD, &hscfg);
  698. mwifiex_enable_hs(priv->adapter);
  699. clear_bit(MWIFIEX_IS_HS_ENABLING, &priv->adapter->work_flags);
  700. ret = count;
  701. done:
  702. kfree(buf);
  703. return ret;
  704. }
  705. /* Proc hscfg file read handler
  706. * This function can be used to read host sleep configuration
  707. * parameters from driver.
  708. */
  709. static ssize_t
  710. mwifiex_hscfg_read(struct file *file, char __user *ubuf,
  711. size_t count, loff_t *ppos)
  712. {
  713. struct mwifiex_private *priv = (void *)file->private_data;
  714. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  715. char *buf = (char *)addr;
  716. int pos, ret;
  717. struct mwifiex_ds_hs_cfg hscfg;
  718. if (!buf)
  719. return -ENOMEM;
  720. mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
  721. MWIFIEX_SYNC_CMD, &hscfg);
  722. pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
  723. hscfg.gpio, hscfg.gap);
  724. ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
  725. free_page(addr);
  726. return ret;
  727. }
  728. static ssize_t
  729. mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf,
  730. size_t count, loff_t *ppos)
  731. {
  732. struct mwifiex_private *priv = file->private_data;
  733. char buf[3];
  734. bool timeshare_coex;
  735. int ret;
  736. unsigned int len;
  737. if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
  738. return -EOPNOTSUPP;
  739. ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
  740. HostCmd_ACT_GEN_GET, 0, &timeshare_coex, true);
  741. if (ret)
  742. return ret;
  743. len = sprintf(buf, "%d\n", timeshare_coex);
  744. return simple_read_from_buffer(ubuf, count, ppos, buf, len);
  745. }
  746. static ssize_t
  747. mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf,
  748. size_t count, loff_t *ppos)
  749. {
  750. bool timeshare_coex;
  751. struct mwifiex_private *priv = file->private_data;
  752. char kbuf[16];
  753. int ret;
  754. if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
  755. return -EOPNOTSUPP;
  756. memset(kbuf, 0, sizeof(kbuf));
  757. if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count)))
  758. return -EFAULT;
  759. if (strtobool(kbuf, &timeshare_coex))
  760. return -EINVAL;
  761. ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
  762. HostCmd_ACT_GEN_SET, 0, &timeshare_coex, true);
  763. if (ret)
  764. return ret;
  765. else
  766. return count;
  767. }
  768. static ssize_t
  769. mwifiex_reset_write(struct file *file,
  770. const char __user *ubuf, size_t count, loff_t *ppos)
  771. {
  772. struct mwifiex_private *priv = file->private_data;
  773. struct mwifiex_adapter *adapter = priv->adapter;
  774. bool result;
  775. int rc;
  776. rc = kstrtobool_from_user(ubuf, count, &result);
  777. if (rc)
  778. return rc;
  779. if (!result)
  780. return -EINVAL;
  781. if (adapter->if_ops.card_reset) {
  782. dev_info(adapter->dev, "Resetting per request\n");
  783. adapter->if_ops.card_reset(adapter);
  784. }
  785. return count;
  786. }
  787. #define MWIFIEX_DFS_ADD_FILE(name) do { \
  788. debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv, \
  789. &mwifiex_dfs_##name##_fops); \
  790. } while (0);
  791. #define MWIFIEX_DFS_FILE_OPS(name) \
  792. static const struct file_operations mwifiex_dfs_##name##_fops = { \
  793. .read = mwifiex_##name##_read, \
  794. .write = mwifiex_##name##_write, \
  795. .open = simple_open, \
  796. };
  797. #define MWIFIEX_DFS_FILE_READ_OPS(name) \
  798. static const struct file_operations mwifiex_dfs_##name##_fops = { \
  799. .read = mwifiex_##name##_read, \
  800. .open = simple_open, \
  801. };
  802. #define MWIFIEX_DFS_FILE_WRITE_OPS(name) \
  803. static const struct file_operations mwifiex_dfs_##name##_fops = { \
  804. .write = mwifiex_##name##_write, \
  805. .open = simple_open, \
  806. };
  807. MWIFIEX_DFS_FILE_READ_OPS(info);
  808. MWIFIEX_DFS_FILE_READ_OPS(debug);
  809. MWIFIEX_DFS_FILE_READ_OPS(getlog);
  810. MWIFIEX_DFS_FILE_OPS(regrdwr);
  811. MWIFIEX_DFS_FILE_OPS(rdeeprom);
  812. MWIFIEX_DFS_FILE_OPS(memrw);
  813. MWIFIEX_DFS_FILE_OPS(hscfg);
  814. MWIFIEX_DFS_FILE_OPS(histogram);
  815. MWIFIEX_DFS_FILE_OPS(debug_mask);
  816. MWIFIEX_DFS_FILE_OPS(timeshare_coex);
  817. MWIFIEX_DFS_FILE_WRITE_OPS(reset);
  818. MWIFIEX_DFS_FILE_OPS(verext);
  819. /*
  820. * This function creates the debug FS directory structure and the files.
  821. */
  822. void
  823. mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
  824. {
  825. if (!mwifiex_dfs_dir || !priv)
  826. return;
  827. priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
  828. mwifiex_dfs_dir);
  829. if (!priv->dfs_dev_dir)
  830. return;
  831. MWIFIEX_DFS_ADD_FILE(info);
  832. MWIFIEX_DFS_ADD_FILE(debug);
  833. MWIFIEX_DFS_ADD_FILE(getlog);
  834. MWIFIEX_DFS_ADD_FILE(regrdwr);
  835. MWIFIEX_DFS_ADD_FILE(rdeeprom);
  836. MWIFIEX_DFS_ADD_FILE(memrw);
  837. MWIFIEX_DFS_ADD_FILE(hscfg);
  838. MWIFIEX_DFS_ADD_FILE(histogram);
  839. MWIFIEX_DFS_ADD_FILE(debug_mask);
  840. MWIFIEX_DFS_ADD_FILE(timeshare_coex);
  841. MWIFIEX_DFS_ADD_FILE(reset);
  842. MWIFIEX_DFS_ADD_FILE(verext);
  843. }
  844. /*
  845. * This function removes the debug FS directory structure and the files.
  846. */
  847. void
  848. mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
  849. {
  850. if (!priv)
  851. return;
  852. debugfs_remove_recursive(priv->dfs_dev_dir);
  853. }
  854. /*
  855. * This function creates the top level proc directory.
  856. */
  857. void
  858. mwifiex_debugfs_init(void)
  859. {
  860. if (!mwifiex_dfs_dir)
  861. mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
  862. }
  863. /*
  864. * This function removes the top level proc directory.
  865. */
  866. void
  867. mwifiex_debugfs_remove(void)
  868. {
  869. debugfs_remove(mwifiex_dfs_dir);
  870. }