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