diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/irda/qos.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/irda/qos.c')
-rw-r--r-- | net/irda/qos.c | 774 |
1 files changed, 774 insertions, 0 deletions
diff --git a/net/irda/qos.c b/net/irda/qos.c new file mode 100644 index 000000000000..df732d56cc57 --- /dev/null +++ b/net/irda/qos.c | |||
@@ -0,0 +1,774 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: qos.c | ||
4 | * Version: 1.0 | ||
5 | * Description: IrLAP QoS parameter negotiation | ||
6 | * Status: Stable | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Tue Sep 9 00:00:26 1997 | ||
9 | * Modified at: Sun Jan 30 14:29:16 2000 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * | ||
12 | * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, | ||
13 | * All Rights Reserved. | ||
14 | * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License as | ||
18 | * published by the Free Software Foundation; either version 2 of | ||
19 | * the License, or (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
29 | * MA 02111-1307 USA | ||
30 | * | ||
31 | ********************************************************************/ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | |||
36 | #include <net/irda/irda.h> | ||
37 | #include <net/irda/parameters.h> | ||
38 | #include <net/irda/qos.h> | ||
39 | #include <net/irda/irlap.h> | ||
40 | |||
41 | /* | ||
42 | * Maximum values of the baud rate we negociate with the other end. | ||
43 | * Most often, you don't have to change that, because Linux-IrDA will | ||
44 | * use the maximum offered by the link layer, which usually works fine. | ||
45 | * In some very rare cases, you may want to limit it to lower speeds... | ||
46 | */ | ||
47 | int sysctl_max_baud_rate = 16000000; | ||
48 | /* | ||
49 | * Maximum value of the lap disconnect timer we negociate with the other end. | ||
50 | * Most often, the value below represent the best compromise, but some user | ||
51 | * may want to keep the LAP alive longuer or shorter in case of link failure. | ||
52 | * Remember that the threshold time (early warning) is fixed to 3s... | ||
53 | */ | ||
54 | int sysctl_max_noreply_time = 12; | ||
55 | /* | ||
56 | * Minimum turn time to be applied before transmitting to the peer. | ||
57 | * Nonzero values (usec) are used as lower limit to the per-connection | ||
58 | * mtt value which was announced by the other end during negotiation. | ||
59 | * Might be helpful if the peer device provides too short mtt. | ||
60 | * Default is 10us which means using the unmodified value given by the | ||
61 | * peer except if it's 0 (0 is likely a bug in the other stack). | ||
62 | */ | ||
63 | unsigned sysctl_min_tx_turn_time = 10; | ||
64 | /* | ||
65 | * Maximum data size to be used in transmission in payload of LAP frame. | ||
66 | * There is a bit of confusion in the IrDA spec : | ||
67 | * The LAP spec defines the payload of a LAP frame (I field) to be | ||
68 | * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). | ||
69 | * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY | ||
70 | * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header | ||
71 | * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP | ||
72 | * payload), that's only 2042 bytes. Oups ! | ||
73 | * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s, | ||
74 | * so adjust to 2042... I don't know if this bug applies only for 2048 | ||
75 | * bytes frames or all negotiated frame sizes, but you can use the sysctl | ||
76 | * to play with this value anyway. | ||
77 | * Jean II */ | ||
78 | unsigned sysctl_max_tx_data_size = 2042; | ||
79 | /* | ||
80 | * Maximum transmit window, i.e. number of LAP frames between turn-around. | ||
81 | * This allow to override what the peer told us. Some peers are buggy and | ||
82 | * don't always support what they tell us. | ||
83 | * Jean II */ | ||
84 | unsigned sysctl_max_tx_window = 7; | ||
85 | |||
86 | static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); | ||
87 | static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, | ||
88 | int get); | ||
89 | static int irlap_param_max_turn_time(void *instance, irda_param_t *param, | ||
90 | int get); | ||
91 | static int irlap_param_data_size(void *instance, irda_param_t *param, int get); | ||
92 | static int irlap_param_window_size(void *instance, irda_param_t *param, | ||
93 | int get); | ||
94 | static int irlap_param_additional_bofs(void *instance, irda_param_t *parm, | ||
95 | int get); | ||
96 | static int irlap_param_min_turn_time(void *instance, irda_param_t *param, | ||
97 | int get); | ||
98 | |||
99 | #ifndef CONFIG_IRDA_DYNAMIC_WINDOW | ||
100 | static __u32 irlap_requested_line_capacity(struct qos_info *qos); | ||
101 | #endif | ||
102 | |||
103 | static __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ | ||
104 | static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, | ||
105 | 1152000, 4000000, 16000000 }; /* bps */ | ||
106 | static __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */ | ||
107 | static __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */ | ||
108 | static __u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */ | ||
109 | static __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */ | ||
110 | |||
111 | static __u32 max_line_capacities[10][4] = { | ||
112 | /* 500 ms 250 ms 100 ms 50 ms (max turn time) */ | ||
113 | { 100, 0, 0, 0 }, /* 2400 bps */ | ||
114 | { 400, 0, 0, 0 }, /* 9600 bps */ | ||
115 | { 800, 0, 0, 0 }, /* 19200 bps */ | ||
116 | { 1600, 0, 0, 0 }, /* 38400 bps */ | ||
117 | { 2360, 0, 0, 0 }, /* 57600 bps */ | ||
118 | { 4800, 2400, 960, 480 }, /* 115200 bps */ | ||
119 | { 28800, 11520, 5760, 2880 }, /* 576000 bps */ | ||
120 | { 57600, 28800, 11520, 5760 }, /* 1152000 bps */ | ||
121 | { 200000, 100000, 40000, 20000 }, /* 4000000 bps */ | ||
122 | { 800000, 400000, 160000, 80000 }, /* 16000000 bps */ | ||
123 | }; | ||
124 | |||
125 | static pi_minor_info_t pi_minor_call_table_type_0[] = { | ||
126 | { NULL, 0 }, | ||
127 | /* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN }, | ||
128 | { NULL, 0 }, | ||
129 | { NULL, 0 }, | ||
130 | { NULL, 0 }, | ||
131 | { NULL, 0 }, | ||
132 | { NULL, 0 }, | ||
133 | { NULL, 0 }, | ||
134 | /* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS } | ||
135 | }; | ||
136 | |||
137 | static pi_minor_info_t pi_minor_call_table_type_1[] = { | ||
138 | { NULL, 0 }, | ||
139 | { NULL, 0 }, | ||
140 | /* 82 */{ irlap_param_max_turn_time, PV_INT_8_BITS }, | ||
141 | /* 83 */{ irlap_param_data_size, PV_INT_8_BITS }, | ||
142 | /* 84 */{ irlap_param_window_size, PV_INT_8_BITS }, | ||
143 | /* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS }, | ||
144 | /* 86 */{ irlap_param_min_turn_time, PV_INT_8_BITS }, | ||
145 | }; | ||
146 | |||
147 | static pi_major_info_t pi_major_call_table[] = { | ||
148 | { pi_minor_call_table_type_0, 9 }, | ||
149 | { pi_minor_call_table_type_1, 7 }, | ||
150 | }; | ||
151 | |||
152 | static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 }; | ||
153 | |||
154 | /* ---------------------- LOCAL SUBROUTINES ---------------------- */ | ||
155 | /* Note : we start with a bunch of local subroutines. | ||
156 | * As the compiler is "one pass", this is the only way to get them to | ||
157 | * inline properly... | ||
158 | * Jean II | ||
159 | */ | ||
160 | /* | ||
161 | * Function value_index (value, array, size) | ||
162 | * | ||
163 | * Returns the index to the value in the specified array | ||
164 | */ | ||
165 | static inline int value_index(__u32 value, __u32 *array, int size) | ||
166 | { | ||
167 | int i; | ||
168 | |||
169 | for (i=0; i < size; i++) | ||
170 | if (array[i] == value) | ||
171 | break; | ||
172 | return i; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Function index_value (index, array) | ||
177 | * | ||
178 | * Returns value to index in array, easy! | ||
179 | * | ||
180 | */ | ||
181 | static inline __u32 index_value(int index, __u32 *array) | ||
182 | { | ||
183 | return array[index]; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Function msb_index (word) | ||
188 | * | ||
189 | * Returns index to most significant bit (MSB) in word | ||
190 | * | ||
191 | */ | ||
192 | static int msb_index (__u16 word) | ||
193 | { | ||
194 | __u16 msb = 0x8000; | ||
195 | int index = 15; /* Current MSB */ | ||
196 | |||
197 | /* Check for buggy peers. | ||
198 | * Note : there is a small probability that it could be us, but I | ||
199 | * would expect driver authors to catch that pretty early and be | ||
200 | * able to check precisely what's going on. If a end user sees this, | ||
201 | * it's very likely the peer. - Jean II */ | ||
202 | if (word == 0) { | ||
203 | IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n", | ||
204 | __FUNCTION__); | ||
205 | /* The only safe choice (we don't know the array size) */ | ||
206 | word = 0x1; | ||
207 | } | ||
208 | |||
209 | while (msb) { | ||
210 | if (word & msb) | ||
211 | break; /* Found it! */ | ||
212 | msb >>=1; | ||
213 | index--; | ||
214 | } | ||
215 | return index; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Function value_lower_bits (value, array) | ||
220 | * | ||
221 | * Returns a bit field marking all possibility lower than value. | ||
222 | */ | ||
223 | static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field) | ||
224 | { | ||
225 | int i; | ||
226 | __u16 mask = 0x1; | ||
227 | __u16 result = 0x0; | ||
228 | |||
229 | for (i=0; i < size; i++) { | ||
230 | /* Add the current value to the bit field, shift mask */ | ||
231 | result |= mask; | ||
232 | mask <<= 1; | ||
233 | /* Finished ? */ | ||
234 | if (array[i] >= value) | ||
235 | break; | ||
236 | } | ||
237 | /* Send back a valid index */ | ||
238 | if(i >= size) | ||
239 | i = size - 1; /* Last item */ | ||
240 | *field = result; | ||
241 | return i; | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Function value_highest_bit (value, array) | ||
246 | * | ||
247 | * Returns a bit field marking the highest possibility lower than value. | ||
248 | */ | ||
249 | static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field) | ||
250 | { | ||
251 | int i; | ||
252 | __u16 mask = 0x1; | ||
253 | __u16 result = 0x0; | ||
254 | |||
255 | for (i=0; i < size; i++) { | ||
256 | /* Finished ? */ | ||
257 | if (array[i] <= value) | ||
258 | break; | ||
259 | /* Shift mask */ | ||
260 | mask <<= 1; | ||
261 | } | ||
262 | /* Set the current value to the bit field */ | ||
263 | result |= mask; | ||
264 | /* Send back a valid index */ | ||
265 | if(i >= size) | ||
266 | i = size - 1; /* Last item */ | ||
267 | *field = result; | ||
268 | return i; | ||
269 | } | ||
270 | |||
271 | /* -------------------------- MAIN CALLS -------------------------- */ | ||
272 | |||
273 | /* | ||
274 | * Function irda_qos_compute_intersection (qos, new) | ||
275 | * | ||
276 | * Compute the intersection of the old QoS capabilities with new ones | ||
277 | * | ||
278 | */ | ||
279 | void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new) | ||
280 | { | ||
281 | IRDA_ASSERT(qos != NULL, return;); | ||
282 | IRDA_ASSERT(new != NULL, return;); | ||
283 | |||
284 | /* Apply */ | ||
285 | qos->baud_rate.bits &= new->baud_rate.bits; | ||
286 | qos->window_size.bits &= new->window_size.bits; | ||
287 | qos->min_turn_time.bits &= new->min_turn_time.bits; | ||
288 | qos->max_turn_time.bits &= new->max_turn_time.bits; | ||
289 | qos->data_size.bits &= new->data_size.bits; | ||
290 | qos->link_disc_time.bits &= new->link_disc_time.bits; | ||
291 | qos->additional_bofs.bits &= new->additional_bofs.bits; | ||
292 | |||
293 | irda_qos_bits_to_value(qos); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * Function irda_init_max_qos_capabilies (qos) | ||
298 | * | ||
299 | * The purpose of this function is for layers and drivers to be able to | ||
300 | * set the maximum QoS possible and then "and in" their own limitations | ||
301 | * | ||
302 | */ | ||
303 | void irda_init_max_qos_capabilies(struct qos_info *qos) | ||
304 | { | ||
305 | int i; | ||
306 | /* | ||
307 | * These are the maximum supported values as specified on pages | ||
308 | * 39-43 in IrLAP | ||
309 | */ | ||
310 | |||
311 | /* Use sysctl to set some configurable values... */ | ||
312 | /* Set configured max speed */ | ||
313 | i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10, | ||
314 | &qos->baud_rate.bits); | ||
315 | sysctl_max_baud_rate = index_value(i, baud_rates); | ||
316 | |||
317 | /* Set configured max disc time */ | ||
318 | i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8, | ||
319 | &qos->link_disc_time.bits); | ||
320 | sysctl_max_noreply_time = index_value(i, link_disc_times); | ||
321 | |||
322 | /* LSB is first byte, MSB is second byte */ | ||
323 | qos->baud_rate.bits &= 0x03ff; | ||
324 | |||
325 | qos->window_size.bits = 0x7f; | ||
326 | qos->min_turn_time.bits = 0xff; | ||
327 | qos->max_turn_time.bits = 0x0f; | ||
328 | qos->data_size.bits = 0x3f; | ||
329 | qos->link_disc_time.bits &= 0xff; | ||
330 | qos->additional_bofs.bits = 0xff; | ||
331 | } | ||
332 | EXPORT_SYMBOL(irda_init_max_qos_capabilies); | ||
333 | |||
334 | /* | ||
335 | * Function irlap_adjust_qos_settings (qos) | ||
336 | * | ||
337 | * Adjust QoS settings in case some values are not possible to use because | ||
338 | * of other settings | ||
339 | */ | ||
340 | static void irlap_adjust_qos_settings(struct qos_info *qos) | ||
341 | { | ||
342 | __u32 line_capacity; | ||
343 | int index; | ||
344 | |||
345 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
346 | |||
347 | /* | ||
348 | * Make sure the mintt is sensible. | ||
349 | * Main culprit : Ericsson T39. - Jean II | ||
350 | */ | ||
351 | if (sysctl_min_tx_turn_time > qos->min_turn_time.value) { | ||
352 | int i; | ||
353 | |||
354 | IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n", | ||
355 | __FUNCTION__, sysctl_min_tx_turn_time); | ||
356 | |||
357 | /* We don't really need bits, but easier this way */ | ||
358 | i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times, | ||
359 | 8, &qos->min_turn_time.bits); | ||
360 | sysctl_min_tx_turn_time = index_value(i, min_turn_times); | ||
361 | qos->min_turn_time.value = sysctl_min_tx_turn_time; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Not allowed to use a max turn time less than 500 ms if the baudrate | ||
366 | * is less than 115200 | ||
367 | */ | ||
368 | if ((qos->baud_rate.value < 115200) && | ||
369 | (qos->max_turn_time.value < 500)) | ||
370 | { | ||
371 | IRDA_DEBUG(0, | ||
372 | "%s(), adjusting max turn time from %d to 500 ms\n", | ||
373 | __FUNCTION__, qos->max_turn_time.value); | ||
374 | qos->max_turn_time.value = 500; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * The data size must be adjusted according to the baud rate and max | ||
379 | * turn time | ||
380 | */ | ||
381 | index = value_index(qos->data_size.value, data_sizes, 6); | ||
382 | line_capacity = irlap_max_line_capacity(qos->baud_rate.value, | ||
383 | qos->max_turn_time.value); | ||
384 | |||
385 | #ifdef CONFIG_IRDA_DYNAMIC_WINDOW | ||
386 | while ((qos->data_size.value > line_capacity) && (index > 0)) { | ||
387 | qos->data_size.value = data_sizes[index--]; | ||
388 | IRDA_DEBUG(2, "%s(), reducing data size to %d\n", | ||
389 | __FUNCTION__, qos->data_size.value); | ||
390 | } | ||
391 | #else /* Use method described in section 6.6.11 of IrLAP */ | ||
392 | while (irlap_requested_line_capacity(qos) > line_capacity) { | ||
393 | IRDA_ASSERT(index != 0, return;); | ||
394 | |||
395 | /* Must be able to send at least one frame */ | ||
396 | if (qos->window_size.value > 1) { | ||
397 | qos->window_size.value--; | ||
398 | IRDA_DEBUG(2, "%s(), reducing window size to %d\n", | ||
399 | __FUNCTION__, qos->window_size.value); | ||
400 | } else if (index > 1) { | ||
401 | qos->data_size.value = data_sizes[index--]; | ||
402 | IRDA_DEBUG(2, "%s(), reducing data size to %d\n", | ||
403 | __FUNCTION__, qos->data_size.value); | ||
404 | } else { | ||
405 | IRDA_WARNING("%s(), nothing more we can do!\n", | ||
406 | __FUNCTION__); | ||
407 | } | ||
408 | } | ||
409 | #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ | ||
410 | /* | ||
411 | * Fix tx data size according to user limits - Jean II | ||
412 | */ | ||
413 | if (qos->data_size.value > sysctl_max_tx_data_size) | ||
414 | /* Allow non discrete adjustement to avoid loosing capacity */ | ||
415 | qos->data_size.value = sysctl_max_tx_data_size; | ||
416 | /* | ||
417 | * Override Tx window if user request it. - Jean II | ||
418 | */ | ||
419 | if (qos->window_size.value > sysctl_max_tx_window) | ||
420 | qos->window_size.value = sysctl_max_tx_window; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * Function irlap_negotiate (qos_device, qos_session, skb) | ||
425 | * | ||
426 | * Negotiate QoS values, not really that much negotiation :-) | ||
427 | * We just set the QoS capabilities for the peer station | ||
428 | * | ||
429 | */ | ||
430 | int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) | ||
431 | { | ||
432 | int ret; | ||
433 | |||
434 | ret = irda_param_extract_all(self, skb->data, skb->len, | ||
435 | &irlap_param_info); | ||
436 | |||
437 | /* Convert the negotiated bits to values */ | ||
438 | irda_qos_bits_to_value(&self->qos_tx); | ||
439 | irda_qos_bits_to_value(&self->qos_rx); | ||
440 | |||
441 | irlap_adjust_qos_settings(&self->qos_tx); | ||
442 | |||
443 | IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n", | ||
444 | self->qos_tx.baud_rate.value); | ||
445 | IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n", | ||
446 | self->qos_tx.data_size.value); | ||
447 | IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n", | ||
448 | self->qos_tx.window_size.value); | ||
449 | IRDA_DEBUG(2, "Setting XBOFS to %d\n", | ||
450 | self->qos_tx.additional_bofs.value); | ||
451 | IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n", | ||
452 | self->qos_tx.max_turn_time.value); | ||
453 | IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n", | ||
454 | self->qos_tx.min_turn_time.value); | ||
455 | IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n", | ||
456 | self->qos_tx.link_disc_time.value); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Function irlap_insert_negotiation_params (qos, fp) | ||
462 | * | ||
463 | * Insert QoS negotiaion pararameters into frame | ||
464 | * | ||
465 | */ | ||
466 | int irlap_insert_qos_negotiation_params(struct irlap_cb *self, | ||
467 | struct sk_buff *skb) | ||
468 | { | ||
469 | int ret; | ||
470 | |||
471 | /* Insert data rate */ | ||
472 | ret = irda_param_insert(self, PI_BAUD_RATE, skb->tail, | ||
473 | skb_tailroom(skb), &irlap_param_info); | ||
474 | if (ret < 0) | ||
475 | return ret; | ||
476 | skb_put(skb, ret); | ||
477 | |||
478 | /* Insert max turnaround time */ | ||
479 | ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb->tail, | ||
480 | skb_tailroom(skb), &irlap_param_info); | ||
481 | if (ret < 0) | ||
482 | return ret; | ||
483 | skb_put(skb, ret); | ||
484 | |||
485 | /* Insert data size */ | ||
486 | ret = irda_param_insert(self, PI_DATA_SIZE, skb->tail, | ||
487 | skb_tailroom(skb), &irlap_param_info); | ||
488 | if (ret < 0) | ||
489 | return ret; | ||
490 | skb_put(skb, ret); | ||
491 | |||
492 | /* Insert window size */ | ||
493 | ret = irda_param_insert(self, PI_WINDOW_SIZE, skb->tail, | ||
494 | skb_tailroom(skb), &irlap_param_info); | ||
495 | if (ret < 0) | ||
496 | return ret; | ||
497 | skb_put(skb, ret); | ||
498 | |||
499 | /* Insert additional BOFs */ | ||
500 | ret = irda_param_insert(self, PI_ADD_BOFS, skb->tail, | ||
501 | skb_tailroom(skb), &irlap_param_info); | ||
502 | if (ret < 0) | ||
503 | return ret; | ||
504 | skb_put(skb, ret); | ||
505 | |||
506 | /* Insert minimum turnaround time */ | ||
507 | ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb->tail, | ||
508 | skb_tailroom(skb), &irlap_param_info); | ||
509 | if (ret < 0) | ||
510 | return ret; | ||
511 | skb_put(skb, ret); | ||
512 | |||
513 | /* Insert link disconnect/threshold time */ | ||
514 | ret = irda_param_insert(self, PI_LINK_DISC, skb->tail, | ||
515 | skb_tailroom(skb), &irlap_param_info); | ||
516 | if (ret < 0) | ||
517 | return ret; | ||
518 | skb_put(skb, ret); | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * Function irlap_param_baud_rate (instance, param, get) | ||
525 | * | ||
526 | * Negotiate data-rate | ||
527 | * | ||
528 | */ | ||
529 | static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get) | ||
530 | { | ||
531 | __u16 final; | ||
532 | |||
533 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
534 | |||
535 | IRDA_ASSERT(self != NULL, return -1;); | ||
536 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
537 | |||
538 | if (get) { | ||
539 | param->pv.i = self->qos_rx.baud_rate.bits; | ||
540 | IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n", | ||
541 | __FUNCTION__, param->pv.i); | ||
542 | } else { | ||
543 | /* | ||
544 | * Stations must agree on baud rate, so calculate | ||
545 | * intersection | ||
546 | */ | ||
547 | IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", (__u16) param->pv.i); | ||
548 | final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits; | ||
549 | |||
550 | IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final); | ||
551 | self->qos_tx.baud_rate.bits = final; | ||
552 | self->qos_rx.baud_rate.bits = final; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Function irlap_param_link_disconnect (instance, param, get) | ||
560 | * | ||
561 | * Negotiate link disconnect/threshold time. | ||
562 | * | ||
563 | */ | ||
564 | static int irlap_param_link_disconnect(void *instance, irda_param_t *param, | ||
565 | int get) | ||
566 | { | ||
567 | __u16 final; | ||
568 | |||
569 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
570 | |||
571 | IRDA_ASSERT(self != NULL, return -1;); | ||
572 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
573 | |||
574 | if (get) | ||
575 | param->pv.i = self->qos_rx.link_disc_time.bits; | ||
576 | else { | ||
577 | /* | ||
578 | * Stations must agree on link disconnect/threshold | ||
579 | * time. | ||
580 | */ | ||
581 | IRDA_DEBUG(2, "LINK_DISC: %02x\n", (__u8) param->pv.i); | ||
582 | final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits; | ||
583 | |||
584 | IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final); | ||
585 | self->qos_tx.link_disc_time.bits = final; | ||
586 | self->qos_rx.link_disc_time.bits = final; | ||
587 | } | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * Function irlap_param_max_turn_time (instance, param, get) | ||
593 | * | ||
594 | * Negotiate the maximum turnaround time. This is a type 1 parameter and | ||
595 | * will be negotiated independently for each station | ||
596 | * | ||
597 | */ | ||
598 | static int irlap_param_max_turn_time(void *instance, irda_param_t *param, | ||
599 | int get) | ||
600 | { | ||
601 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
602 | |||
603 | IRDA_ASSERT(self != NULL, return -1;); | ||
604 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
605 | |||
606 | if (get) | ||
607 | param->pv.i = self->qos_rx.max_turn_time.bits; | ||
608 | else | ||
609 | self->qos_tx.max_turn_time.bits = (__u8) param->pv.i; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * Function irlap_param_data_size (instance, param, get) | ||
616 | * | ||
617 | * Negotiate the data size. This is a type 1 parameter and | ||
618 | * will be negotiated independently for each station | ||
619 | * | ||
620 | */ | ||
621 | static int irlap_param_data_size(void *instance, irda_param_t *param, int get) | ||
622 | { | ||
623 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
624 | |||
625 | IRDA_ASSERT(self != NULL, return -1;); | ||
626 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
627 | |||
628 | if (get) | ||
629 | param->pv.i = self->qos_rx.data_size.bits; | ||
630 | else | ||
631 | self->qos_tx.data_size.bits = (__u8) param->pv.i; | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * Function irlap_param_window_size (instance, param, get) | ||
638 | * | ||
639 | * Negotiate the window size. This is a type 1 parameter and | ||
640 | * will be negotiated independently for each station | ||
641 | * | ||
642 | */ | ||
643 | static int irlap_param_window_size(void *instance, irda_param_t *param, | ||
644 | int get) | ||
645 | { | ||
646 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
647 | |||
648 | IRDA_ASSERT(self != NULL, return -1;); | ||
649 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
650 | |||
651 | if (get) | ||
652 | param->pv.i = self->qos_rx.window_size.bits; | ||
653 | else | ||
654 | self->qos_tx.window_size.bits = (__u8) param->pv.i; | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * Function irlap_param_additional_bofs (instance, param, get) | ||
661 | * | ||
662 | * Negotiate additional BOF characters. This is a type 1 parameter and | ||
663 | * will be negotiated independently for each station. | ||
664 | */ | ||
665 | static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get) | ||
666 | { | ||
667 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
668 | |||
669 | IRDA_ASSERT(self != NULL, return -1;); | ||
670 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
671 | |||
672 | if (get) | ||
673 | param->pv.i = self->qos_rx.additional_bofs.bits; | ||
674 | else | ||
675 | self->qos_tx.additional_bofs.bits = (__u8) param->pv.i; | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Function irlap_param_min_turn_time (instance, param, get) | ||
682 | * | ||
683 | * Negotiate the minimum turn around time. This is a type 1 parameter and | ||
684 | * will be negotiated independently for each station | ||
685 | */ | ||
686 | static int irlap_param_min_turn_time(void *instance, irda_param_t *param, | ||
687 | int get) | ||
688 | { | ||
689 | struct irlap_cb *self = (struct irlap_cb *) instance; | ||
690 | |||
691 | IRDA_ASSERT(self != NULL, return -1;); | ||
692 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | ||
693 | |||
694 | if (get) | ||
695 | param->pv.i = self->qos_rx.min_turn_time.bits; | ||
696 | else | ||
697 | self->qos_tx.min_turn_time.bits = (__u8) param->pv.i; | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | /* | ||
703 | * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time) | ||
704 | * | ||
705 | * Calculate the maximum line capacity | ||
706 | * | ||
707 | */ | ||
708 | __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time) | ||
709 | { | ||
710 | __u32 line_capacity; | ||
711 | int i,j; | ||
712 | |||
713 | IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n", | ||
714 | __FUNCTION__, speed, max_turn_time); | ||
715 | |||
716 | i = value_index(speed, baud_rates, 10); | ||
717 | j = value_index(max_turn_time, max_turn_times, 4); | ||
718 | |||
719 | IRDA_ASSERT(((i >=0) && (i <10)), return 0;); | ||
720 | IRDA_ASSERT(((j >=0) && (j <4)), return 0;); | ||
721 | |||
722 | line_capacity = max_line_capacities[i][j]; | ||
723 | |||
724 | IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n", | ||
725 | __FUNCTION__, line_capacity); | ||
726 | |||
727 | return line_capacity; | ||
728 | } | ||
729 | |||
730 | #ifndef CONFIG_IRDA_DYNAMIC_WINDOW | ||
731 | static __u32 irlap_requested_line_capacity(struct qos_info *qos) | ||
732 | { | ||
733 | __u32 line_capacity; | ||
734 | |||
735 | line_capacity = qos->window_size.value * | ||
736 | (qos->data_size.value + 6 + qos->additional_bofs.value) + | ||
737 | irlap_min_turn_time_in_bytes(qos->baud_rate.value, | ||
738 | qos->min_turn_time.value); | ||
739 | |||
740 | IRDA_DEBUG(2, "%s(), requested line capacity=%d\n", | ||
741 | __FUNCTION__, line_capacity); | ||
742 | |||
743 | return line_capacity; | ||
744 | } | ||
745 | #endif | ||
746 | |||
747 | void irda_qos_bits_to_value(struct qos_info *qos) | ||
748 | { | ||
749 | int index; | ||
750 | |||
751 | IRDA_ASSERT(qos != NULL, return;); | ||
752 | |||
753 | index = msb_index(qos->baud_rate.bits); | ||
754 | qos->baud_rate.value = baud_rates[index]; | ||
755 | |||
756 | index = msb_index(qos->data_size.bits); | ||
757 | qos->data_size.value = data_sizes[index]; | ||
758 | |||
759 | index = msb_index(qos->window_size.bits); | ||
760 | qos->window_size.value = index+1; | ||
761 | |||
762 | index = msb_index(qos->min_turn_time.bits); | ||
763 | qos->min_turn_time.value = min_turn_times[index]; | ||
764 | |||
765 | index = msb_index(qos->max_turn_time.bits); | ||
766 | qos->max_turn_time.value = max_turn_times[index]; | ||
767 | |||
768 | index = msb_index(qos->link_disc_time.bits); | ||
769 | qos->link_disc_time.value = link_disc_times[index]; | ||
770 | |||
771 | index = msb_index(qos->additional_bofs.bits); | ||
772 | qos->additional_bofs.value = add_bofs[index]; | ||
773 | } | ||
774 | EXPORT_SYMBOL(irda_qos_bits_to_value); | ||