debugfs.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. #include <linux/dcache.h>
  2. #include <linux/debugfs.h>
  3. #include <linux/delay.h>
  4. #include <linux/mm.h>
  5. #include <linux/string.h>
  6. #include <linux/slab.h>
  7. #include "decl.h"
  8. #include "cmd.h"
  9. #include "debugfs.h"
  10. static struct dentry *lbs_dir;
  11. static char *szStates[] = {
  12. "Connected",
  13. "Disconnected"
  14. };
  15. #ifdef PROC_DEBUG
  16. static void lbs_debug_init(struct lbs_private *priv);
  17. #endif
  18. static int open_file_generic(struct inode *inode, struct file *file)
  19. {
  20. file->private_data = inode->i_private;
  21. return 0;
  22. }
  23. static ssize_t write_file_dummy(struct file *file, const char __user *buf,
  24. size_t count, loff_t *ppos)
  25. {
  26. return -EINVAL;
  27. }
  28. static const size_t len = PAGE_SIZE;
  29. static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
  30. size_t count, loff_t *ppos)
  31. {
  32. struct lbs_private *priv = file->private_data;
  33. size_t pos = 0;
  34. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  35. char *buf = (char *)addr;
  36. ssize_t res;
  37. if (!buf)
  38. return -ENOMEM;
  39. pos += snprintf(buf+pos, len-pos, "state = %s\n",
  40. szStates[priv->connect_status]);
  41. pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
  42. (u32) priv->regioncode);
  43. res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  44. free_page(addr);
  45. return res;
  46. }
  47. static ssize_t lbs_sleepparams_write(struct file *file,
  48. const char __user *user_buf, size_t count,
  49. loff_t *ppos)
  50. {
  51. struct lbs_private *priv = file->private_data;
  52. ssize_t buf_size, ret;
  53. struct sleep_params sp;
  54. int p1, p2, p3, p4, p5, p6;
  55. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  56. char *buf = (char *)addr;
  57. if (!buf)
  58. return -ENOMEM;
  59. buf_size = min(count, len - 1);
  60. if (copy_from_user(buf, user_buf, buf_size)) {
  61. ret = -EFAULT;
  62. goto out_unlock;
  63. }
  64. ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
  65. if (ret != 6) {
  66. ret = -EINVAL;
  67. goto out_unlock;
  68. }
  69. sp.sp_error = p1;
  70. sp.sp_offset = p2;
  71. sp.sp_stabletime = p3;
  72. sp.sp_calcontrol = p4;
  73. sp.sp_extsleepclk = p5;
  74. sp.sp_reserved = p6;
  75. ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
  76. if (!ret)
  77. ret = count;
  78. else if (ret > 0)
  79. ret = -EINVAL;
  80. out_unlock:
  81. free_page(addr);
  82. return ret;
  83. }
  84. static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
  85. size_t count, loff_t *ppos)
  86. {
  87. struct lbs_private *priv = file->private_data;
  88. ssize_t ret;
  89. size_t pos = 0;
  90. struct sleep_params sp;
  91. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  92. char *buf = (char *)addr;
  93. if (!buf)
  94. return -ENOMEM;
  95. ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
  96. if (ret)
  97. goto out_unlock;
  98. pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
  99. sp.sp_offset, sp.sp_stabletime,
  100. sp.sp_calcontrol, sp.sp_extsleepclk,
  101. sp.sp_reserved);
  102. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  103. out_unlock:
  104. free_page(addr);
  105. return ret;
  106. }
  107. static ssize_t lbs_host_sleep_write(struct file *file,
  108. const char __user *user_buf, size_t count,
  109. loff_t *ppos)
  110. {
  111. struct lbs_private *priv = file->private_data;
  112. ssize_t buf_size, ret;
  113. int host_sleep;
  114. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  115. char *buf = (char *)addr;
  116. if (!buf)
  117. return -ENOMEM;
  118. buf_size = min(count, len - 1);
  119. if (copy_from_user(buf, user_buf, buf_size)) {
  120. ret = -EFAULT;
  121. goto out_unlock;
  122. }
  123. ret = sscanf(buf, "%d", &host_sleep);
  124. if (ret != 1) {
  125. ret = -EINVAL;
  126. goto out_unlock;
  127. }
  128. if (host_sleep == 0)
  129. ret = lbs_set_host_sleep(priv, 0);
  130. else if (host_sleep == 1) {
  131. if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
  132. lbs_pr_info("wake parameters not configured");
  133. ret = -EINVAL;
  134. goto out_unlock;
  135. }
  136. ret = lbs_set_host_sleep(priv, 1);
  137. } else {
  138. lbs_pr_err("invalid option\n");
  139. ret = -EINVAL;
  140. }
  141. if (!ret)
  142. ret = count;
  143. out_unlock:
  144. free_page(addr);
  145. return ret;
  146. }
  147. static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
  148. size_t count, loff_t *ppos)
  149. {
  150. struct lbs_private *priv = file->private_data;
  151. ssize_t ret;
  152. size_t pos = 0;
  153. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  154. char *buf = (char *)addr;
  155. if (!buf)
  156. return -ENOMEM;
  157. pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
  158. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  159. free_page(addr);
  160. return ret;
  161. }
  162. /*
  163. * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
  164. * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
  165. * firmware. Here's an example:
  166. * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
  167. * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
  168. * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  169. *
  170. * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
  171. * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
  172. * defined in mrvlietypes_thresholds
  173. *
  174. * This function searches in this TLV data chunk for a given TLV type
  175. * and returns a pointer to the first data byte of the TLV, or to NULL
  176. * if the TLV hasn't been found.
  177. */
  178. static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
  179. {
  180. struct mrvl_ie_header *tlv_h;
  181. uint16_t length;
  182. ssize_t pos = 0;
  183. while (pos < size) {
  184. tlv_h = (struct mrvl_ie_header *) tlv;
  185. if (!tlv_h->len)
  186. return NULL;
  187. if (tlv_h->type == cpu_to_le16(tlv_type))
  188. return tlv_h;
  189. length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
  190. pos += length;
  191. tlv += length;
  192. }
  193. return NULL;
  194. }
  195. static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
  196. struct file *file, char __user *userbuf,
  197. size_t count, loff_t *ppos)
  198. {
  199. struct cmd_ds_802_11_subscribe_event *subscribed;
  200. struct mrvl_ie_thresholds *got;
  201. struct lbs_private *priv = file->private_data;
  202. ssize_t ret = 0;
  203. size_t pos = 0;
  204. char *buf;
  205. u8 value;
  206. u8 freq;
  207. int events = 0;
  208. buf = (char *)get_zeroed_page(GFP_KERNEL);
  209. if (!buf)
  210. return -ENOMEM;
  211. subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
  212. if (!subscribed) {
  213. ret = -ENOMEM;
  214. goto out_page;
  215. }
  216. subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
  217. subscribed->action = cpu_to_le16(CMD_ACT_GET);
  218. ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
  219. if (ret)
  220. goto out_cmd;
  221. got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
  222. if (got) {
  223. value = got->value;
  224. freq = got->freq;
  225. events = le16_to_cpu(subscribed->events);
  226. pos += snprintf(buf, len, "%d %d %d\n", value, freq,
  227. !!(events & event_mask));
  228. }
  229. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  230. out_cmd:
  231. kfree(subscribed);
  232. out_page:
  233. free_page((unsigned long)buf);
  234. return ret;
  235. }
  236. static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
  237. struct file *file,
  238. const char __user *userbuf, size_t count,
  239. loff_t *ppos)
  240. {
  241. struct cmd_ds_802_11_subscribe_event *events;
  242. struct mrvl_ie_thresholds *tlv;
  243. struct lbs_private *priv = file->private_data;
  244. ssize_t buf_size;
  245. int value, freq, new_mask;
  246. uint16_t curr_mask;
  247. char *buf;
  248. int ret;
  249. buf = (char *)get_zeroed_page(GFP_KERNEL);
  250. if (!buf)
  251. return -ENOMEM;
  252. buf_size = min(count, len - 1);
  253. if (copy_from_user(buf, userbuf, buf_size)) {
  254. ret = -EFAULT;
  255. goto out_page;
  256. }
  257. ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
  258. if (ret != 3) {
  259. ret = -EINVAL;
  260. goto out_page;
  261. }
  262. events = kzalloc(sizeof(*events), GFP_KERNEL);
  263. if (!events) {
  264. ret = -ENOMEM;
  265. goto out_page;
  266. }
  267. events->hdr.size = cpu_to_le16(sizeof(*events));
  268. events->action = cpu_to_le16(CMD_ACT_GET);
  269. ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
  270. if (ret)
  271. goto out_events;
  272. curr_mask = le16_to_cpu(events->events);
  273. if (new_mask)
  274. new_mask = curr_mask | event_mask;
  275. else
  276. new_mask = curr_mask & ~event_mask;
  277. /* Now everything is set and we can send stuff down to the firmware */
  278. tlv = (void *)events->tlv;
  279. events->action = cpu_to_le16(CMD_ACT_SET);
  280. events->events = cpu_to_le16(new_mask);
  281. tlv->header.type = cpu_to_le16(tlv_type);
  282. tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
  283. tlv->value = value;
  284. if (tlv_type != TLV_TYPE_BCNMISS)
  285. tlv->freq = freq;
  286. /* The command header, the action, the event mask, and one TLV */
  287. events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
  288. ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
  289. if (!ret)
  290. ret = count;
  291. out_events:
  292. kfree(events);
  293. out_page:
  294. free_page((unsigned long)buf);
  295. return ret;
  296. }
  297. static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
  298. size_t count, loff_t *ppos)
  299. {
  300. return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
  301. file, userbuf, count, ppos);
  302. }
  303. static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
  304. size_t count, loff_t *ppos)
  305. {
  306. return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
  307. file, userbuf, count, ppos);
  308. }
  309. static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
  310. size_t count, loff_t *ppos)
  311. {
  312. return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
  313. file, userbuf, count, ppos);
  314. }
  315. static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
  316. size_t count, loff_t *ppos)
  317. {
  318. return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
  319. file, userbuf, count, ppos);
  320. }
  321. static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
  322. size_t count, loff_t *ppos)
  323. {
  324. return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
  325. file, userbuf, count, ppos);
  326. }
  327. static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
  328. size_t count, loff_t *ppos)
  329. {
  330. return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
  331. file, userbuf, count, ppos);
  332. }
  333. static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
  334. size_t count, loff_t *ppos)
  335. {
  336. return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
  337. file, userbuf, count, ppos);
  338. }
  339. static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
  340. size_t count, loff_t *ppos)
  341. {
  342. return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
  343. file, userbuf, count, ppos);
  344. }
  345. static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
  346. size_t count, loff_t *ppos)
  347. {
  348. return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
  349. file, userbuf, count, ppos);
  350. }
  351. static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
  352. size_t count, loff_t *ppos)
  353. {
  354. return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
  355. file, userbuf, count, ppos);
  356. }
  357. static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
  358. size_t count, loff_t *ppos)
  359. {
  360. return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
  361. file, userbuf, count, ppos);
  362. }
  363. static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
  364. size_t count, loff_t *ppos)
  365. {
  366. return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
  367. file, userbuf, count, ppos);
  368. }
  369. static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
  370. size_t count, loff_t *ppos)
  371. {
  372. struct lbs_private *priv = file->private_data;
  373. struct lbs_offset_value offval;
  374. ssize_t pos = 0;
  375. int ret;
  376. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  377. char *buf = (char *)addr;
  378. if (!buf)
  379. return -ENOMEM;
  380. offval.offset = priv->mac_offset;
  381. offval.value = 0;
  382. ret = lbs_prepare_and_send_command(priv,
  383. CMD_MAC_REG_ACCESS, 0,
  384. CMD_OPTION_WAITFORRSP, 0, &offval);
  385. mdelay(10);
  386. if (!ret) {
  387. pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
  388. priv->mac_offset, priv->offsetvalue.value);
  389. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  390. }
  391. free_page(addr);
  392. return ret;
  393. }
  394. static ssize_t lbs_rdmac_write(struct file *file,
  395. const char __user *userbuf,
  396. size_t count, loff_t *ppos)
  397. {
  398. struct lbs_private *priv = file->private_data;
  399. ssize_t res, buf_size;
  400. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  401. char *buf = (char *)addr;
  402. if (!buf)
  403. return -ENOMEM;
  404. buf_size = min(count, len - 1);
  405. if (copy_from_user(buf, userbuf, buf_size)) {
  406. res = -EFAULT;
  407. goto out_unlock;
  408. }
  409. priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
  410. res = count;
  411. out_unlock:
  412. free_page(addr);
  413. return res;
  414. }
  415. static ssize_t lbs_wrmac_write(struct file *file,
  416. const char __user *userbuf,
  417. size_t count, loff_t *ppos)
  418. {
  419. struct lbs_private *priv = file->private_data;
  420. ssize_t res, buf_size;
  421. u32 offset, value;
  422. struct lbs_offset_value offval;
  423. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  424. char *buf = (char *)addr;
  425. if (!buf)
  426. return -ENOMEM;
  427. buf_size = min(count, len - 1);
  428. if (copy_from_user(buf, userbuf, buf_size)) {
  429. res = -EFAULT;
  430. goto out_unlock;
  431. }
  432. res = sscanf(buf, "%x %x", &offset, &value);
  433. if (res != 2) {
  434. res = -EFAULT;
  435. goto out_unlock;
  436. }
  437. offval.offset = offset;
  438. offval.value = value;
  439. res = lbs_prepare_and_send_command(priv,
  440. CMD_MAC_REG_ACCESS, 1,
  441. CMD_OPTION_WAITFORRSP, 0, &offval);
  442. mdelay(10);
  443. if (!res)
  444. res = count;
  445. out_unlock:
  446. free_page(addr);
  447. return res;
  448. }
  449. static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
  450. size_t count, loff_t *ppos)
  451. {
  452. struct lbs_private *priv = file->private_data;
  453. struct lbs_offset_value offval;
  454. ssize_t pos = 0;
  455. int ret;
  456. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  457. char *buf = (char *)addr;
  458. if (!buf)
  459. return -ENOMEM;
  460. offval.offset = priv->bbp_offset;
  461. offval.value = 0;
  462. ret = lbs_prepare_and_send_command(priv,
  463. CMD_BBP_REG_ACCESS, 0,
  464. CMD_OPTION_WAITFORRSP, 0, &offval);
  465. mdelay(10);
  466. if (!ret) {
  467. pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
  468. priv->bbp_offset, priv->offsetvalue.value);
  469. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  470. }
  471. free_page(addr);
  472. return ret;
  473. }
  474. static ssize_t lbs_rdbbp_write(struct file *file,
  475. const char __user *userbuf,
  476. size_t count, loff_t *ppos)
  477. {
  478. struct lbs_private *priv = file->private_data;
  479. ssize_t res, buf_size;
  480. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  481. char *buf = (char *)addr;
  482. if (!buf)
  483. return -ENOMEM;
  484. buf_size = min(count, len - 1);
  485. if (copy_from_user(buf, userbuf, buf_size)) {
  486. res = -EFAULT;
  487. goto out_unlock;
  488. }
  489. priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
  490. res = count;
  491. out_unlock:
  492. free_page(addr);
  493. return res;
  494. }
  495. static ssize_t lbs_wrbbp_write(struct file *file,
  496. const char __user *userbuf,
  497. size_t count, loff_t *ppos)
  498. {
  499. struct lbs_private *priv = file->private_data;
  500. ssize_t res, buf_size;
  501. u32 offset, value;
  502. struct lbs_offset_value offval;
  503. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  504. char *buf = (char *)addr;
  505. if (!buf)
  506. return -ENOMEM;
  507. buf_size = min(count, len - 1);
  508. if (copy_from_user(buf, userbuf, buf_size)) {
  509. res = -EFAULT;
  510. goto out_unlock;
  511. }
  512. res = sscanf(buf, "%x %x", &offset, &value);
  513. if (res != 2) {
  514. res = -EFAULT;
  515. goto out_unlock;
  516. }
  517. offval.offset = offset;
  518. offval.value = value;
  519. res = lbs_prepare_and_send_command(priv,
  520. CMD_BBP_REG_ACCESS, 1,
  521. CMD_OPTION_WAITFORRSP, 0, &offval);
  522. mdelay(10);
  523. if (!res)
  524. res = count;
  525. out_unlock:
  526. free_page(addr);
  527. return res;
  528. }
  529. static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
  530. size_t count, loff_t *ppos)
  531. {
  532. struct lbs_private *priv = file->private_data;
  533. struct lbs_offset_value offval;
  534. ssize_t pos = 0;
  535. int ret;
  536. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  537. char *buf = (char *)addr;
  538. if (!buf)
  539. return -ENOMEM;
  540. offval.offset = priv->rf_offset;
  541. offval.value = 0;
  542. ret = lbs_prepare_and_send_command(priv,
  543. CMD_RF_REG_ACCESS, 0,
  544. CMD_OPTION_WAITFORRSP, 0, &offval);
  545. mdelay(10);
  546. if (!ret) {
  547. pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
  548. priv->rf_offset, priv->offsetvalue.value);
  549. ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
  550. }
  551. free_page(addr);
  552. return ret;
  553. }
  554. static ssize_t lbs_rdrf_write(struct file *file,
  555. const char __user *userbuf,
  556. size_t count, loff_t *ppos)
  557. {
  558. struct lbs_private *priv = file->private_data;
  559. ssize_t res, buf_size;
  560. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  561. char *buf = (char *)addr;
  562. if (!buf)
  563. return -ENOMEM;
  564. buf_size = min(count, len - 1);
  565. if (copy_from_user(buf, userbuf, buf_size)) {
  566. res = -EFAULT;
  567. goto out_unlock;
  568. }
  569. priv->rf_offset = simple_strtoul(buf, NULL, 16);
  570. res = count;
  571. out_unlock:
  572. free_page(addr);
  573. return res;
  574. }
  575. static ssize_t lbs_wrrf_write(struct file *file,
  576. const char __user *userbuf,
  577. size_t count, loff_t *ppos)
  578. {
  579. struct lbs_private *priv = file->private_data;
  580. ssize_t res, buf_size;
  581. u32 offset, value;
  582. struct lbs_offset_value offval;
  583. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  584. char *buf = (char *)addr;
  585. if (!buf)
  586. return -ENOMEM;
  587. buf_size = min(count, len - 1);
  588. if (copy_from_user(buf, userbuf, buf_size)) {
  589. res = -EFAULT;
  590. goto out_unlock;
  591. }
  592. res = sscanf(buf, "%x %x", &offset, &value);
  593. if (res != 2) {
  594. res = -EFAULT;
  595. goto out_unlock;
  596. }
  597. offval.offset = offset;
  598. offval.value = value;
  599. res = lbs_prepare_and_send_command(priv,
  600. CMD_RF_REG_ACCESS, 1,
  601. CMD_OPTION_WAITFORRSP, 0, &offval);
  602. mdelay(10);
  603. if (!res)
  604. res = count;
  605. out_unlock:
  606. free_page(addr);
  607. return res;
  608. }
  609. #define FOPS(fread, fwrite) { \
  610. .owner = THIS_MODULE, \
  611. .open = open_file_generic, \
  612. .read = (fread), \
  613. .write = (fwrite), \
  614. }
  615. struct lbs_debugfs_files {
  616. const char *name;
  617. int perm;
  618. struct file_operations fops;
  619. };
  620. static const struct lbs_debugfs_files debugfs_files[] = {
  621. { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
  622. { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
  623. lbs_sleepparams_write), },
  624. { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
  625. lbs_host_sleep_write), },
  626. };
  627. static const struct lbs_debugfs_files debugfs_events_files[] = {
  628. {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
  629. lbs_lowrssi_write), },
  630. {"low_snr", 0644, FOPS(lbs_lowsnr_read,
  631. lbs_lowsnr_write), },
  632. {"failure_count", 0644, FOPS(lbs_failcount_read,
  633. lbs_failcount_write), },
  634. {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
  635. lbs_bcnmiss_write), },
  636. {"high_rssi", 0644, FOPS(lbs_highrssi_read,
  637. lbs_highrssi_write), },
  638. {"high_snr", 0644, FOPS(lbs_highsnr_read,
  639. lbs_highsnr_write), },
  640. };
  641. static const struct lbs_debugfs_files debugfs_regs_files[] = {
  642. {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
  643. {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
  644. {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
  645. {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
  646. {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
  647. {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
  648. };
  649. void lbs_debugfs_init(void)
  650. {
  651. if (!lbs_dir)
  652. lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
  653. }
  654. void lbs_debugfs_remove(void)
  655. {
  656. if (lbs_dir)
  657. debugfs_remove(lbs_dir);
  658. }
  659. void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
  660. {
  661. int i;
  662. const struct lbs_debugfs_files *files;
  663. if (!lbs_dir)
  664. goto exit;
  665. priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
  666. if (!priv->debugfs_dir)
  667. goto exit;
  668. for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
  669. files = &debugfs_files[i];
  670. priv->debugfs_files[i] = debugfs_create_file(files->name,
  671. files->perm,
  672. priv->debugfs_dir,
  673. priv,
  674. &files->fops);
  675. }
  676. priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
  677. if (!priv->events_dir)
  678. goto exit;
  679. for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
  680. files = &debugfs_events_files[i];
  681. priv->debugfs_events_files[i] = debugfs_create_file(files->name,
  682. files->perm,
  683. priv->events_dir,
  684. priv,
  685. &files->fops);
  686. }
  687. priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
  688. if (!priv->regs_dir)
  689. goto exit;
  690. for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
  691. files = &debugfs_regs_files[i];
  692. priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
  693. files->perm,
  694. priv->regs_dir,
  695. priv,
  696. &files->fops);
  697. }
  698. #ifdef PROC_DEBUG
  699. lbs_debug_init(priv);
  700. #endif
  701. exit:
  702. return;
  703. }
  704. void lbs_debugfs_remove_one(struct lbs_private *priv)
  705. {
  706. int i;
  707. for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
  708. debugfs_remove(priv->debugfs_regs_files[i]);
  709. debugfs_remove(priv->regs_dir);
  710. for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
  711. debugfs_remove(priv->debugfs_events_files[i]);
  712. debugfs_remove(priv->events_dir);
  713. #ifdef PROC_DEBUG
  714. debugfs_remove(priv->debugfs_debug);
  715. #endif
  716. for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
  717. debugfs_remove(priv->debugfs_files[i]);
  718. debugfs_remove(priv->debugfs_dir);
  719. }
  720. /* debug entry */
  721. #ifdef PROC_DEBUG
  722. #define item_size(n) (FIELD_SIZEOF(struct lbs_private, n))
  723. #define item_addr(n) (offsetof(struct lbs_private, n))
  724. struct debug_data {
  725. char name[32];
  726. u32 size;
  727. size_t addr;
  728. };
  729. /* To debug any member of struct lbs_private, simply add one line here.
  730. */
  731. static struct debug_data items[] = {
  732. {"psmode", item_size(psmode), item_addr(psmode)},
  733. {"psstate", item_size(psstate), item_addr(psstate)},
  734. };
  735. static int num_of_items = ARRAY_SIZE(items);
  736. /**
  737. * @brief proc read function
  738. *
  739. * @param page pointer to buffer
  740. * @param s read data starting position
  741. * @param off offset
  742. * @param cnt counter
  743. * @param eof end of file flag
  744. * @param data data to output
  745. * @return number of output data
  746. */
  747. static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
  748. size_t count, loff_t *ppos)
  749. {
  750. int val = 0;
  751. size_t pos = 0;
  752. ssize_t res;
  753. char *p;
  754. int i;
  755. struct debug_data *d;
  756. unsigned long addr = get_zeroed_page(GFP_KERNEL);
  757. char *buf = (char *)addr;
  758. if (!buf)
  759. return -ENOMEM;
  760. p = buf;
  761. d = (struct debug_data *)file->private_data;
  762. for (i = 0; i < num_of_items; i++) {
  763. if (d[i].size == 1)
  764. val = *((u8 *) d[i].addr);
  765. else if (d[i].size == 2)
  766. val = *((u16 *) d[i].addr);
  767. else if (d[i].size == 4)
  768. val = *((u32 *) d[i].addr);
  769. else if (d[i].size == 8)
  770. val = *((u64 *) d[i].addr);
  771. pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
  772. }
  773. res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
  774. free_page(addr);
  775. return res;
  776. }
  777. /**
  778. * @brief proc write function
  779. *
  780. * @param f file pointer
  781. * @param buf pointer to data buffer
  782. * @param cnt data number to write
  783. * @param data data to write
  784. * @return number of data
  785. */
  786. static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
  787. size_t cnt, loff_t *ppos)
  788. {
  789. int r, i;
  790. char *pdata;
  791. char *p;
  792. char *p0;
  793. char *p1;
  794. char *p2;
  795. struct debug_data *d = (struct debug_data *)f->private_data;
  796. pdata = kmalloc(cnt, GFP_KERNEL);
  797. if (pdata == NULL)
  798. return 0;
  799. if (copy_from_user(pdata, buf, cnt)) {
  800. lbs_deb_debugfs("Copy from user failed\n");
  801. kfree(pdata);
  802. return 0;
  803. }
  804. p0 = pdata;
  805. for (i = 0; i < num_of_items; i++) {
  806. do {
  807. p = strstr(p0, d[i].name);
  808. if (p == NULL)
  809. break;
  810. p1 = strchr(p, '\n');
  811. if (p1 == NULL)
  812. break;
  813. p0 = p1++;
  814. p2 = strchr(p, '=');
  815. if (!p2)
  816. break;
  817. p2++;
  818. r = simple_strtoul(p2, NULL, 0);
  819. if (d[i].size == 1)
  820. *((u8 *) d[i].addr) = (u8) r;
  821. else if (d[i].size == 2)
  822. *((u16 *) d[i].addr) = (u16) r;
  823. else if (d[i].size == 4)
  824. *((u32 *) d[i].addr) = (u32) r;
  825. else if (d[i].size == 8)
  826. *((u64 *) d[i].addr) = (u64) r;
  827. break;
  828. } while (1);
  829. }
  830. kfree(pdata);
  831. return (ssize_t)cnt;
  832. }
  833. static const struct file_operations lbs_debug_fops = {
  834. .owner = THIS_MODULE,
  835. .open = open_file_generic,
  836. .write = lbs_debugfs_write,
  837. .read = lbs_debugfs_read,
  838. };
  839. /**
  840. * @brief create debug proc file
  841. *
  842. * @param priv pointer struct lbs_private
  843. * @param dev pointer net_device
  844. * @return N/A
  845. */
  846. static void lbs_debug_init(struct lbs_private *priv)
  847. {
  848. int i;
  849. if (!priv->debugfs_dir)
  850. return;
  851. for (i = 0; i < num_of_items; i++)
  852. items[i].addr += (size_t) priv;
  853. priv->debugfs_debug = debugfs_create_file("debug", 0644,
  854. priv->debugfs_dir, &items[0],
  855. &lbs_debug_fops);
  856. }
  857. #endif