est.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Ultra Wide Band Radio Control
  3. * Event Size Tables management
  4. *
  5. * Copyright (C) 2005-2006 Intel Corporation
  6. * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License version
  10. * 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20. * 02110-1301, USA.
  21. *
  22. *
  23. * FIXME: docs
  24. *
  25. * Infrastructure, code and data tables for guessing the size of
  26. * events received on the notification endpoints of UWB radio
  27. * controllers.
  28. *
  29. * You define a table of events and for each, its size and how to get
  30. * the extra size.
  31. *
  32. * ENTRY POINTS:
  33. *
  34. * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
  35. *
  36. * uwb_est_[u]register(): To un/register event size tables
  37. * uwb_est_grow()
  38. *
  39. * uwb_est_find_size(): Get the size of an event
  40. * uwb_est_get_size()
  41. */
  42. #include <linux/spinlock.h>
  43. #include <linux/slab.h>
  44. #include "uwb-internal.h"
  45. struct uwb_est {
  46. u16 type_event_high;
  47. u16 vendor, product;
  48. u8 entries;
  49. const struct uwb_est_entry *entry;
  50. };
  51. static struct uwb_est *uwb_est;
  52. static u8 uwb_est_size;
  53. static u8 uwb_est_used;
  54. static DEFINE_RWLOCK(uwb_est_lock);
  55. /**
  56. * WUSB Standard Event Size Table, HWA-RC interface
  57. *
  58. * Sizes for events and notifications type 0 (general), high nibble 0.
  59. */
  60. static
  61. struct uwb_est_entry uwb_est_00_00xx[] = {
  62. [UWB_RC_EVT_IE_RCV] = {
  63. .size = sizeof(struct uwb_rc_evt_ie_rcv),
  64. .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
  65. },
  66. [UWB_RC_EVT_BEACON] = {
  67. .size = sizeof(struct uwb_rc_evt_beacon),
  68. .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
  69. },
  70. [UWB_RC_EVT_BEACON_SIZE] = {
  71. .size = sizeof(struct uwb_rc_evt_beacon_size),
  72. },
  73. [UWB_RC_EVT_BPOIE_CHANGE] = {
  74. .size = sizeof(struct uwb_rc_evt_bpoie_change),
  75. .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
  76. wBPOIELength),
  77. },
  78. [UWB_RC_EVT_BP_SLOT_CHANGE] = {
  79. .size = sizeof(struct uwb_rc_evt_bp_slot_change),
  80. },
  81. [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
  82. .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
  83. .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
  84. },
  85. [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
  86. .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
  87. },
  88. [UWB_RC_EVT_DRP_AVAIL] = {
  89. .size = sizeof(struct uwb_rc_evt_drp_avail)
  90. },
  91. [UWB_RC_EVT_DRP] = {
  92. .size = sizeof(struct uwb_rc_evt_drp),
  93. .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
  94. },
  95. [UWB_RC_EVT_BP_SWITCH_STATUS] = {
  96. .size = sizeof(struct uwb_rc_evt_bp_switch_status),
  97. },
  98. [UWB_RC_EVT_CMD_FRAME_RCV] = {
  99. .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
  100. .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
  101. },
  102. [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
  103. .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
  104. .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
  105. },
  106. [UWB_RC_CMD_CHANNEL_CHANGE] = {
  107. .size = sizeof(struct uwb_rc_evt_confirm),
  108. },
  109. [UWB_RC_CMD_DEV_ADDR_MGMT] = {
  110. .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
  111. [UWB_RC_CMD_GET_IE] = {
  112. .size = sizeof(struct uwb_rc_evt_get_ie),
  113. .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
  114. },
  115. [UWB_RC_CMD_RESET] = {
  116. .size = sizeof(struct uwb_rc_evt_confirm),
  117. },
  118. [UWB_RC_CMD_SCAN] = {
  119. .size = sizeof(struct uwb_rc_evt_confirm),
  120. },
  121. [UWB_RC_CMD_SET_BEACON_FILTER] = {
  122. .size = sizeof(struct uwb_rc_evt_confirm),
  123. },
  124. [UWB_RC_CMD_SET_DRP_IE] = {
  125. .size = sizeof(struct uwb_rc_evt_set_drp_ie),
  126. },
  127. [UWB_RC_CMD_SET_IE] = {
  128. .size = sizeof(struct uwb_rc_evt_set_ie),
  129. },
  130. [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
  131. .size = sizeof(struct uwb_rc_evt_confirm),
  132. },
  133. [UWB_RC_CMD_SET_TX_POWER] = {
  134. .size = sizeof(struct uwb_rc_evt_confirm),
  135. },
  136. [UWB_RC_CMD_SLEEP] = {
  137. .size = sizeof(struct uwb_rc_evt_confirm),
  138. },
  139. [UWB_RC_CMD_START_BEACON] = {
  140. .size = sizeof(struct uwb_rc_evt_confirm),
  141. },
  142. [UWB_RC_CMD_STOP_BEACON] = {
  143. .size = sizeof(struct uwb_rc_evt_confirm),
  144. },
  145. [UWB_RC_CMD_BP_MERGE] = {
  146. .size = sizeof(struct uwb_rc_evt_confirm),
  147. },
  148. [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
  149. .size = sizeof(struct uwb_rc_evt_confirm),
  150. },
  151. [UWB_RC_CMD_SET_ASIE_NOTIF] = {
  152. .size = sizeof(struct uwb_rc_evt_confirm),
  153. },
  154. };
  155. static
  156. struct uwb_est_entry uwb_est_01_00xx[] = {
  157. [UWB_RC_DAA_ENERGY_DETECTED] = {
  158. .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
  159. },
  160. [UWB_RC_SET_DAA_ENERGY_MASK] = {
  161. .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
  162. },
  163. [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
  164. .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
  165. },
  166. };
  167. /**
  168. * Initialize the EST subsystem
  169. *
  170. * Register the standard tables also.
  171. *
  172. * FIXME: tag init
  173. */
  174. int uwb_est_create(void)
  175. {
  176. int result;
  177. uwb_est_size = 2;
  178. uwb_est_used = 0;
  179. uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL);
  180. if (uwb_est == NULL)
  181. return -ENOMEM;
  182. result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
  183. uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
  184. if (result < 0)
  185. goto out;
  186. result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
  187. uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
  188. out:
  189. return result;
  190. }
  191. /** Clean it up */
  192. void uwb_est_destroy(void)
  193. {
  194. kfree(uwb_est);
  195. uwb_est = NULL;
  196. uwb_est_size = uwb_est_used = 0;
  197. }
  198. /**
  199. * Double the capacity of the EST table
  200. *
  201. * @returns 0 if ok, < 0 errno no error.
  202. */
  203. static
  204. int uwb_est_grow(void)
  205. {
  206. size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
  207. void *new = kmalloc(2 * actual_size, GFP_ATOMIC);
  208. if (new == NULL)
  209. return -ENOMEM;
  210. memcpy(new, uwb_est, actual_size);
  211. memset(new + actual_size, 0, actual_size);
  212. kfree(uwb_est);
  213. uwb_est = new;
  214. uwb_est_size *= 2;
  215. return 0;
  216. }
  217. /**
  218. * Register an event size table
  219. *
  220. * Makes room for it if the table is full, and then inserts it in the
  221. * right position (entries are sorted by type, event_high, vendor and
  222. * then product).
  223. *
  224. * @vendor: vendor code for matching against the device (0x0000 and
  225. * 0xffff mean any); use 0x0000 to force all to match without
  226. * checking possible vendor specific ones, 0xfffff to match
  227. * after checking vendor specific ones.
  228. *
  229. * @product: product code from that vendor; same matching rules, use
  230. * 0x0000 for not allowing vendor specific matches, 0xffff
  231. * for allowing.
  232. *
  233. * This arragement just makes the tables sort differenty. Because the
  234. * table is sorted by growing type-event_high-vendor-product, a zero
  235. * vendor will match before than a 0x456a vendor, that will match
  236. * before a 0xfffff vendor.
  237. *
  238. * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
  239. */
  240. /* FIXME: add bus type to vendor/product code */
  241. int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
  242. const struct uwb_est_entry *entry, size_t entries)
  243. {
  244. unsigned long flags;
  245. unsigned itr;
  246. u16 type_event_high;
  247. int result = 0;
  248. write_lock_irqsave(&uwb_est_lock, flags);
  249. if (uwb_est_used == uwb_est_size) {
  250. result = uwb_est_grow();
  251. if (result < 0)
  252. goto out;
  253. }
  254. /* Find the right spot to insert it in */
  255. type_event_high = type << 8 | event_high;
  256. for (itr = 0; itr < uwb_est_used; itr++)
  257. if (uwb_est[itr].type_event_high < type
  258. && uwb_est[itr].vendor < vendor
  259. && uwb_est[itr].product < product)
  260. break;
  261. /* Shift others to make room for the new one? */
  262. if (itr < uwb_est_used)
  263. memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
  264. uwb_est[itr].type_event_high = type << 8 | event_high;
  265. uwb_est[itr].vendor = vendor;
  266. uwb_est[itr].product = product;
  267. uwb_est[itr].entry = entry;
  268. uwb_est[itr].entries = entries;
  269. uwb_est_used++;
  270. out:
  271. write_unlock_irqrestore(&uwb_est_lock, flags);
  272. return result;
  273. }
  274. EXPORT_SYMBOL_GPL(uwb_est_register);
  275. /**
  276. * Unregister an event size table
  277. *
  278. * This just removes the specified entry and moves the ones after it
  279. * to fill in the gap. This is needed to keep the list sorted; no
  280. * reallocation is done to reduce the size of the table.
  281. *
  282. * We unregister by all the data we used to register instead of by
  283. * pointer to the @entry array because we might have used the same
  284. * table for a bunch of IDs (for example).
  285. *
  286. * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
  287. */
  288. int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
  289. const struct uwb_est_entry *entry, size_t entries)
  290. {
  291. unsigned long flags;
  292. unsigned itr;
  293. struct uwb_est est_cmp = {
  294. .type_event_high = type << 8 | event_high,
  295. .vendor = vendor,
  296. .product = product,
  297. .entry = entry,
  298. .entries = entries
  299. };
  300. write_lock_irqsave(&uwb_est_lock, flags);
  301. for (itr = 0; itr < uwb_est_used; itr++)
  302. if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
  303. goto found;
  304. write_unlock_irqrestore(&uwb_est_lock, flags);
  305. return -ENOENT;
  306. found:
  307. if (itr < uwb_est_used - 1) /* Not last one? move ones above */
  308. memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
  309. uwb_est_used--;
  310. write_unlock_irqrestore(&uwb_est_lock, flags);
  311. return 0;
  312. }
  313. EXPORT_SYMBOL_GPL(uwb_est_unregister);
  314. /**
  315. * Get the size of an event from a table
  316. *
  317. * @rceb: pointer to the buffer with the event
  318. * @rceb_size: size of the area pointed to by @rceb in bytes.
  319. * @returns: > 0 Size of the event
  320. * -ENOSPC An area big enough was not provided to look
  321. * ahead into the event's guts and guess the size.
  322. * -EINVAL Unknown event code (wEvent).
  323. *
  324. * This will look at the received RCEB and guess what is the total
  325. * size. For variable sized events, it will look further ahead into
  326. * their length field to see how much data should be read.
  327. *
  328. * Note this size is *not* final--the neh (Notification/Event Handle)
  329. * might specificy an extra size to add.
  330. */
  331. static
  332. ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
  333. u8 event_low, const struct uwb_rceb *rceb,
  334. size_t rceb_size)
  335. {
  336. unsigned offset;
  337. ssize_t size;
  338. struct device *dev = &uwb_rc->uwb_dev.dev;
  339. const struct uwb_est_entry *entry;
  340. size = -ENOENT;
  341. if (event_low >= est->entries) { /* in range? */
  342. dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
  343. est, est->type_event_high, est->vendor, est->product,
  344. est->entries, event_low);
  345. goto out;
  346. }
  347. size = -ENOENT;
  348. entry = &est->entry[event_low];
  349. if (entry->size == 0 && entry->offset == 0) { /* unknown? */
  350. dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
  351. est, est->type_event_high, est->vendor, est->product,
  352. est->entries, event_low);
  353. goto out;
  354. }
  355. offset = entry->offset; /* extra fries with that? */
  356. if (offset == 0)
  357. size = entry->size;
  358. else {
  359. /* Ops, got an extra size field at 'offset'--read it */
  360. const void *ptr = rceb;
  361. size_t type_size = 0;
  362. offset--;
  363. size = -ENOSPC; /* enough data for more? */
  364. switch (entry->type) {
  365. case UWB_EST_16: type_size = sizeof(__le16); break;
  366. case UWB_EST_8: type_size = sizeof(u8); break;
  367. default: BUG();
  368. }
  369. if (offset + type_size > rceb_size) {
  370. dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
  371. "not enough data to read extra size\n",
  372. est, est->type_event_high, est->vendor,
  373. est->product, est->entries);
  374. goto out;
  375. }
  376. size = entry->size;
  377. ptr += offset;
  378. switch (entry->type) {
  379. case UWB_EST_16: size += le16_to_cpu(*(__le16 *)ptr); break;
  380. case UWB_EST_8: size += *(u8 *)ptr; break;
  381. default: BUG();
  382. }
  383. }
  384. out:
  385. return size;
  386. }
  387. /**
  388. * Guesses the size of a WA event
  389. *
  390. * @rceb: pointer to the buffer with the event
  391. * @rceb_size: size of the area pointed to by @rceb in bytes.
  392. * @returns: > 0 Size of the event
  393. * -ENOSPC An area big enough was not provided to look
  394. * ahead into the event's guts and guess the size.
  395. * -EINVAL Unknown event code (wEvent).
  396. *
  397. * This will look at the received RCEB and guess what is the total
  398. * size by checking all the tables registered with
  399. * uwb_est_register(). For variable sized events, it will look further
  400. * ahead into their length field to see how much data should be read.
  401. *
  402. * Note this size is *not* final--the neh (Notification/Event Handle)
  403. * might specificy an extra size to add or replace.
  404. */
  405. ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
  406. size_t rceb_size)
  407. {
  408. /* FIXME: add vendor/product data */
  409. ssize_t size;
  410. struct device *dev = &rc->uwb_dev.dev;
  411. unsigned long flags;
  412. unsigned itr;
  413. u16 type_event_high, event;
  414. u8 *ptr = (u8 *) rceb;
  415. read_lock_irqsave(&uwb_est_lock, flags);
  416. size = -ENOSPC;
  417. if (rceb_size < sizeof(*rceb))
  418. goto out;
  419. event = le16_to_cpu(rceb->wEvent);
  420. type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
  421. for (itr = 0; itr < uwb_est_used; itr++) {
  422. if (uwb_est[itr].type_event_high != type_event_high)
  423. continue;
  424. size = uwb_est_get_size(rc, &uwb_est[itr],
  425. event & 0x00ff, rceb, rceb_size);
  426. /* try more tables that might handle the same type */
  427. if (size != -ENOENT)
  428. goto out;
  429. }
  430. dev_dbg(dev, "event 0x%02x/%04x/%02x: no handlers available; "
  431. "RCEB %02x %02x %02x %02x\n",
  432. (unsigned) rceb->bEventType,
  433. (unsigned) le16_to_cpu(rceb->wEvent),
  434. (unsigned) rceb->bEventContext,
  435. ptr[0], ptr[1], ptr[2], ptr[3]);
  436. size = -ENOENT;
  437. out:
  438. read_unlock_irqrestore(&uwb_est_lock, flags);
  439. return size;
  440. }
  441. EXPORT_SYMBOL_GPL(uwb_est_find_size);