debugfs.c 27 KB

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