debugfs.c 24 KB

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