]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /********************************************************************* |
6819bc2e | 2 | * |
1da177e4 LT |
3 | * Filename: qos.c |
4 | * Version: 1.0 | |
5 | * Description: IrLAP QoS parameter negotiation | |
6 | * Status: Stable | |
7 | * Author: Dag Brattli <[email protected]> | |
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 <[email protected]> | |
6819bc2e YH |
11 | * |
12 | * Copyright (c) 1998-2000 Dag Brattli <[email protected]>, | |
1da177e4 LT |
13 | * All Rights Reserved. |
14 | * Copyright (c) 2000-2001 Jean Tourrilhes <[email protected]> | |
6819bc2e YH |
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 | |
1da177e4 | 19 | * the License, or (at your option) any later version. |
6819bc2e | 20 | * |
1da177e4 LT |
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. | |
6819bc2e YH |
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, | |
1da177e4 | 29 | * MA 02111-1307 USA |
6819bc2e | 30 | * |
1da177e4 LT |
31 | ********************************************************************/ |
32 | ||
1da177e4 LT |
33 | #include <asm/byteorder.h> |
34 | ||
35 | #include <net/irda/irda.h> | |
36 | #include <net/irda/parameters.h> | |
37 | #include <net/irda/qos.h> | |
38 | #include <net/irda/irlap.h> | |
506e7beb | 39 | #include <net/irda/irlap_frame.h> |
1da177e4 LT |
40 | |
41 | /* | |
25985edc | 42 | * Maximum values of the baud rate we negotiate with the other end. |
1da177e4 LT |
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 | /* | |
25985edc | 49 | * Maximum value of the lap disconnect timer we negotiate with the other end. |
1da177e4 | 50 | * Most often, the value below represent the best compromise, but some user |
25985edc | 51 | * may want to keep the LAP alive longer or shorter in case of link failure. |
1da177e4 LT |
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 | */ | |
9566042e | 63 | unsigned int sysctl_min_tx_turn_time = 10; |
1da177e4 LT |
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 */ | |
9566042e | 78 | unsigned int sysctl_max_tx_data_size = 2042; |
1da177e4 LT |
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 */ | |
9566042e | 84 | unsigned int sysctl_max_tx_window = 7; |
1da177e4 LT |
85 | |
86 | static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); | |
6819bc2e | 87 | static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, |
1da177e4 | 88 | int get); |
6819bc2e | 89 | static int irlap_param_max_turn_time(void *instance, irda_param_t *param, |
1da177e4 LT |
90 | int get); |
91 | static int irlap_param_data_size(void *instance, irda_param_t *param, int get); | |
6819bc2e | 92 | static int irlap_param_window_size(void *instance, irda_param_t *param, |
1da177e4 | 93 | int get); |
6819bc2e | 94 | static int irlap_param_additional_bofs(void *instance, irda_param_t *parm, |
1da177e4 | 95 | int get); |
6819bc2e | 96 | static int irlap_param_min_turn_time(void *instance, irda_param_t *param, |
1da177e4 LT |
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 */ | |
6819bc2e | 104 | static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, |
1da177e4 LT |
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; | |
6819bc2e | 168 | |
1da177e4 LT |
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 | */ | |
6819bc2e | 181 | static inline __u32 index_value(int index, __u32 *array) |
1da177e4 LT |
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 | */ | |
6819bc2e | 192 | static int msb_index (__u16 word) |
1da177e4 LT |
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", | |
0dc47877 | 204 | __func__); |
1da177e4 LT |
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 | |
6819bc2e | 301 | * |
1da177e4 LT |
302 | */ |
303 | void irda_init_max_qos_capabilies(struct qos_info *qos) | |
304 | { | |
305 | int i; | |
6819bc2e | 306 | /* |
1da177e4 LT |
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 | ||
0dc47877 | 345 | IRDA_DEBUG(2, "%s()\n", __func__); |
1da177e4 LT |
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", | |
0dc47877 | 355 | __func__, sysctl_min_tx_turn_time); |
1da177e4 LT |
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 | ||
6819bc2e | 364 | /* |
1da177e4 LT |
365 | * Not allowed to use a max turn time less than 500 ms if the baudrate |
366 | * is less than 115200 | |
367 | */ | |
6819bc2e | 368 | if ((qos->baud_rate.value < 115200) && |
1da177e4 LT |
369 | (qos->max_turn_time.value < 500)) |
370 | { | |
6819bc2e | 371 | IRDA_DEBUG(0, |
1da177e4 | 372 | "%s(), adjusting max turn time from %d to 500 ms\n", |
0dc47877 | 373 | __func__, qos->max_turn_time.value); |
1da177e4 LT |
374 | qos->max_turn_time.value = 500; |
375 | } | |
6819bc2e | 376 | |
1da177e4 | 377 | /* |
6819bc2e | 378 | * The data size must be adjusted according to the baud rate and max |
1da177e4 LT |
379 | * turn time |
380 | */ | |
381 | index = value_index(qos->data_size.value, data_sizes, 6); | |
6819bc2e | 382 | line_capacity = irlap_max_line_capacity(qos->baud_rate.value, |
1da177e4 LT |
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", | |
0dc47877 | 389 | __func__, qos->data_size.value); |
1da177e4 LT |
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", | |
0dc47877 | 399 | __func__, qos->window_size.value); |
1da177e4 LT |
400 | } else if (index > 1) { |
401 | qos->data_size.value = data_sizes[index--]; | |
402 | IRDA_DEBUG(2, "%s(), reducing data size to %d\n", | |
0dc47877 | 403 | __func__, qos->data_size.value); |
1da177e4 LT |
404 | } else { |
405 | IRDA_WARNING("%s(), nothing more we can do!\n", | |
0dc47877 | 406 | __func__); |
1da177e4 LT |
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) | |
25985edc | 414 | /* Allow non discrete adjustement to avoid losing capacity */ |
1da177e4 LT |
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 | */ | |
6819bc2e | 430 | int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) |
1da177e4 LT |
431 | { |
432 | int ret; | |
6819bc2e YH |
433 | |
434 | ret = irda_param_extract_all(self, skb->data, skb->len, | |
1da177e4 | 435 | &irlap_param_info); |
6819bc2e | 436 | |
1da177e4 LT |
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 | ||
6819bc2e | 443 | IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n", |
1da177e4 LT |
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); | |
6819bc2e | 447 | IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n", |
1da177e4 | 448 | self->qos_tx.window_size.value); |
6819bc2e | 449 | IRDA_DEBUG(2, "Setting XBOFS to %d\n", |
1da177e4 LT |
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); | |
6819bc2e | 455 | IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n", |
1da177e4 LT |
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 | */ | |
6819bc2e | 466 | int irlap_insert_qos_negotiation_params(struct irlap_cb *self, |
1da177e4 LT |
467 | struct sk_buff *skb) |
468 | { | |
469 | int ret; | |
470 | ||
471 | /* Insert data rate */ | |
27a884dc | 472 | ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb), |
1da177e4 LT |
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 */ | |
27a884dc | 479 | ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb), |
1da177e4 LT |
480 | skb_tailroom(skb), &irlap_param_info); |
481 | if (ret < 0) | |
482 | return ret; | |
483 | skb_put(skb, ret); | |
484 | ||
485 | /* Insert data size */ | |
27a884dc | 486 | ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb), |
1da177e4 LT |
487 | skb_tailroom(skb), &irlap_param_info); |
488 | if (ret < 0) | |
489 | return ret; | |
490 | skb_put(skb, ret); | |
491 | ||
492 | /* Insert window size */ | |
27a884dc | 493 | ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb), |
1da177e4 LT |
494 | skb_tailroom(skb), &irlap_param_info); |
495 | if (ret < 0) | |
496 | return ret; | |
497 | skb_put(skb, ret); | |
498 | ||
499 | /* Insert additional BOFs */ | |
27a884dc | 500 | ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb), |
1da177e4 LT |
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 */ | |
27a884dc | 507 | ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb), |
1da177e4 LT |
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 */ | |
27a884dc | 514 | ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb), |
1da177e4 LT |
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; | |
6819bc2e | 540 | IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n", |
0dc47877 | 541 | __func__, param->pv.i); |
1da177e4 | 542 | } else { |
6819bc2e | 543 | /* |
1da177e4 | 544 | * Stations must agree on baud rate, so calculate |
6819bc2e | 545 | * intersection |
1da177e4 LT |
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 | * | |
6819bc2e | 561 | * Negotiate link disconnect/threshold time. |
1da177e4 LT |
562 | * |
563 | */ | |
6819bc2e | 564 | static int irlap_param_link_disconnect(void *instance, irda_param_t *param, |
1da177e4 LT |
565 | int get) |
566 | { | |
567 | __u16 final; | |
6819bc2e | 568 | |
1da177e4 | 569 | struct irlap_cb *self = (struct irlap_cb *) instance; |
6819bc2e | 570 | |
1da177e4 LT |
571 | IRDA_ASSERT(self != NULL, return -1;); |
572 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 573 | |
1da177e4 LT |
574 | if (get) |
575 | param->pv.i = self->qos_rx.link_disc_time.bits; | |
576 | else { | |
6819bc2e YH |
577 | /* |
578 | * Stations must agree on link disconnect/threshold | |
1da177e4 LT |
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 | */ | |
6819bc2e | 598 | static int irlap_param_max_turn_time(void *instance, irda_param_t *param, |
1da177e4 LT |
599 | int get) |
600 | { | |
601 | struct irlap_cb *self = (struct irlap_cb *) instance; | |
6819bc2e | 602 | |
1da177e4 LT |
603 | IRDA_ASSERT(self != NULL, return -1;); |
604 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 605 | |
1da177e4 LT |
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; | |
6819bc2e | 624 | |
1da177e4 LT |
625 | IRDA_ASSERT(self != NULL, return -1;); |
626 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 627 | |
1da177e4 LT |
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 | */ | |
6819bc2e | 643 | static int irlap_param_window_size(void *instance, irda_param_t *param, |
1da177e4 LT |
644 | int get) |
645 | { | |
646 | struct irlap_cb *self = (struct irlap_cb *) instance; | |
6819bc2e | 647 | |
1da177e4 LT |
648 | IRDA_ASSERT(self != NULL, return -1;); |
649 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 650 | |
1da177e4 LT |
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; | |
6819bc2e | 668 | |
1da177e4 LT |
669 | IRDA_ASSERT(self != NULL, return -1;); |
670 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 671 | |
1da177e4 LT |
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 | */ | |
6819bc2e | 686 | static int irlap_param_min_turn_time(void *instance, irda_param_t *param, |
1da177e4 LT |
687 | int get) |
688 | { | |
689 | struct irlap_cb *self = (struct irlap_cb *) instance; | |
6819bc2e | 690 | |
1da177e4 LT |
691 | IRDA_ASSERT(self != NULL, return -1;); |
692 | IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); | |
6819bc2e | 693 | |
1da177e4 LT |
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", | |
0dc47877 | 714 | __func__, speed, max_turn_time); |
1da177e4 LT |
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 | ||
6819bc2e | 724 | IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n", |
0dc47877 | 725 | __func__, line_capacity); |
6819bc2e | 726 | |
1da177e4 LT |
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", | |
0dc47877 | 741 | __func__, line_capacity); |
1da177e4 LT |
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;); | |
6819bc2e | 752 | |
1da177e4 LT |
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]; | |
6819bc2e | 764 | |
1da177e4 LT |
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]; | |
6819bc2e | 770 | |
1da177e4 LT |
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); |