Import 2.3.27pre2
[davej-history.git] / net / irda / qos.c
blob0d9a2550bcce900c89d7926835a34cdd2f08bef1
1 /*********************************************************************
2 *
3 *
4 * Filename: qos.c
5 * Version: 1.0
6 * Description: IrLAP QoS parameter negotiation
7 * Status: Experimental.
8 * Author: Dag Brattli <dagb@cs.uit.no>
9 * Created at: Tue Sep 9 00:00:26 1997
10 * Modified at: Tue Oct 5 11:50:41 1999
11 * Modified by: Dag Brattli <dagb@cs.uit.no>
13 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
14 * All Rights Reserved.
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.
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.
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
31 ********************************************************************/
33 #include <linux/config.h>
34 #include <asm/byteorder.h>
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 #ifdef CONFIG_IRDA_COMPRESSION
41 #include <net/irda/irlap_comp.h>
42 #include "../../drivers/net/zlib.h"
44 #define CI_BZIP2 27 /* Random pick */
45 #endif
47 static int irlap_param_baud_rate(void *instance, param_t *param, int get);
48 static int irlap_param_link_disconnect(void *instance, param_t *parm, int get);
49 static int irlap_param_max_turn_time(void *instance, param_t *param, int get);
50 static int irlap_param_data_size(void *instance, param_t *param, int get);
51 static int irlap_param_window_size(void *instance, param_t *param, int get);
52 static int irlap_param_additional_bofs(void *instance, param_t *parm, int get);
53 static int irlap_param_min_turn_time(void *instance, param_t *param, int get);
55 __u32 min_turn_time[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
56 __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
57 1152000, 4000000, 16000000 }; /* bps */
58 __u32 data_size[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */
59 __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */
60 __u32 max_turn_time[] = { 500, 250, 100, 50 }; /* ms */
61 __u32 link_disc_time[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */
63 #ifdef CONFIG_IRDA_COMPRESSION
64 __u32 compression[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
65 #endif
67 static pi_minor_info_t pi_minor_call_table_type_0[] = {
68 { NULL, 0 },
69 /* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN },
70 { NULL, 0 },
71 { NULL, 0 },
72 { NULL, 0 },
73 { NULL, 0 },
74 { NULL, 0 },
75 { NULL, 0 },
76 /* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS }
79 static pi_minor_info_t pi_minor_call_table_type_1[] = {
80 { NULL, 0 },
81 { NULL, 0 },
82 /* 82 */{ irlap_param_max_turn_time, PV_INT_8_BITS },
83 /* 83 */{ irlap_param_data_size, PV_INT_8_BITS },
84 /* 84 */{ irlap_param_window_size, PV_INT_8_BITS },
85 /* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS },
86 /* 86 */{ irlap_param_min_turn_time, PV_INT_8_BITS },
89 static pi_major_info_t pi_major_call_table[] = {
90 { pi_minor_call_table_type_0, 9 },
91 { pi_minor_call_table_type_1, 7 },
94 static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
97 * Function irda_qos_compute_intersection (qos, new)
99 * Compute the intersection of the old QoS capabilites with new ones
102 void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
104 ASSERT(qos != NULL, return;);
105 ASSERT(new != NULL, return;);
107 /* Apply */
108 qos->baud_rate.bits &= new->baud_rate.bits;
109 qos->window_size.bits &= new->window_size.bits;
110 qos->min_turn_time.bits &= new->min_turn_time.bits;
111 qos->max_turn_time.bits &= new->max_turn_time.bits;
112 qos->data_size.bits &= new->data_size.bits;
113 qos->link_disc_time.bits &= new->link_disc_time.bits;
114 qos->additional_bofs.bits &= new->additional_bofs.bits;
116 #ifdef CONFIG_IRDA_COMPRESSION
117 qos->compression.bits &= new->compression.bits;
118 #endif
120 irda_qos_bits_to_value(qos);
124 * Function irda_init_max_qos_capabilies (qos)
126 * The purpose of this function is for layers and drivers to be able to
127 * set the maximum QoS possible and then "and in" their own limitations
130 void irda_init_max_qos_capabilies(struct qos_info *qos)
133 * These are the maximum supported values as specified on pages
134 * 39-43 in IrLAP
137 /* LSB is first byte, MSB is second byte */
138 qos->baud_rate.bits = 0x01ff;
140 qos->window_size.bits = 0x7f;
141 qos->min_turn_time.bits = 0xff;
142 qos->max_turn_time.bits = 0x0f;
143 qos->data_size.bits = 0x3f;
144 qos->link_disc_time.bits = 0xff;
145 qos->additional_bofs.bits = 0xff;
147 #ifdef CONFIG_IRDA_COMPRESSION
148 qos->compression.bits = 0x03;
149 #endif
153 * Function irlap_negotiate (qos_device, qos_session, skb)
155 * Negotiate QoS values, not really that much negotiation :-)
156 * We just set the QoS capabilities for the peer station
159 int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
161 int ret;
162 #ifdef CONFIG_IRDA_COMPRESSION
163 int comp_seen = FALSE;
164 #endif
165 ret = irda_param_extract_all(self, skb->data, skb->len,
166 &irlap_param_info);
168 #ifdef CONFIG_IRDA_COMPRESSION
169 if (!comp_seen) {
170 IRDA_DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
171 self->qos_tx.compression.bits = 0x00;
172 self->qos_rx.compression.bits = 0x00;
174 #endif
176 /* Convert the negotiated bits to values */
177 irda_qos_bits_to_value(&self->qos_tx);
178 irda_qos_bits_to_value(&self->qos_rx);
180 IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
181 self->qos_tx.baud_rate.value);
182 IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
183 self->qos_tx.data_size.value);
184 IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
185 self->qos_tx.window_size.value);
186 IRDA_DEBUG(2, "Setting XBOFS to %d\n",
187 self->qos_tx.additional_bofs.value);
188 IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
189 self->qos_tx.max_turn_time.value);
190 IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
191 self->qos_tx.min_turn_time.value);
192 IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
193 self->qos_tx.link_disc_time.value);
194 #ifdef CONFIG_IRDA_COMPRESSION
195 IRDA_DEBUG(2, "Setting COMPRESSION to %d\n",
196 self->qos_tx.compression.value);
197 #endif
198 return ret;
202 * Function irlap_insert_negotiation_params (qos, fp)
204 * Insert QoS negotiaion pararameters into frame
207 int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
208 struct sk_buff *skb)
210 int ret;
212 /* Insert data rate */
213 ret = irda_param_insert(self, PI_BAUD_RATE, skb->tail,
214 skb_tailroom(skb), &irlap_param_info);
215 if (ret < 0)
216 return ret;
217 skb_put(skb, ret);
219 /* Insert max turnaround time */
220 ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb->tail,
221 skb_tailroom(skb), &irlap_param_info);
222 if (ret < 0)
223 return ret;
224 skb_put(skb, ret);
226 /* Insert data size */
227 ret = irda_param_insert(self, PI_DATA_SIZE, skb->tail,
228 skb_tailroom(skb), &irlap_param_info);
229 if (ret < 0)
230 return ret;
231 skb_put(skb, ret);
233 /* Insert window size */
234 ret = irda_param_insert(self, PI_WINDOW_SIZE, skb->tail,
235 skb_tailroom(skb), &irlap_param_info);
236 if (ret < 0)
237 return ret;
238 skb_put(skb, ret);
240 /* Insert additional BOFs */
241 ret = irda_param_insert(self, PI_ADD_BOFS, skb->tail,
242 skb_tailroom(skb), &irlap_param_info);
243 if (ret < 0)
244 return ret;
245 skb_put(skb, ret);
247 /* Insert minimum turnaround time */
248 ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb->tail,
249 skb_tailroom(skb), &irlap_param_info);
250 if (ret < 0)
251 return ret;
252 skb_put(skb, ret);
254 /* Insert link disconnect/threshold time */
255 ret = irda_param_insert(self, PI_LINK_DISC, skb->tail,
256 skb_tailroom(skb), &irlap_param_info);
257 if (ret < 0)
258 return ret;
259 skb_put(skb, ret);
261 return 0;
265 * Function irlap_param_baud_rate (instance, param, get)
267 * Negotiate data-rate
270 static int irlap_param_baud_rate(void *instance, param_t *param, int get)
272 __u16 final;
274 struct irlap_cb *self = (struct irlap_cb *) instance;
276 ASSERT(self != NULL, return -1;);
277 ASSERT(self->magic == LAP_MAGIC, return -1;);
279 if (get) {
280 param->pv.i = self->qos_rx.baud_rate.bits;
281 IRDA_DEBUG(2, __FUNCTION__ "(), baud rate = 0x%02x\n", param->pv.i);
282 } else {
284 * Stations must agree on baud rate, so calculate
285 * intersection
287 IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", param->pv.s);
288 final = param->pv.s & self->qos_rx.baud_rate.bits;
290 IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
291 self->qos_tx.baud_rate.bits = final;
292 self->qos_rx.baud_rate.bits = final;
295 return 0;
299 * Function irlap_param_link_disconnect (instance, param, get)
301 * Negotiate link disconnect/threshold time.
304 static int irlap_param_link_disconnect(void *instance, param_t *param, int get)
306 __u16 final;
308 struct irlap_cb *self = (struct irlap_cb *) instance;
310 ASSERT(self != NULL, return -1;);
311 ASSERT(self->magic == LAP_MAGIC, return -1;);
313 if (get)
314 param->pv.b = self->qos_rx.link_disc_time.bits;
315 else {
317 * Stations must agree on link disconnect/threshold
318 * time.
320 IRDA_DEBUG(2, "LINK_DISC: %02x\n", param->pv.b);
321 final = param->pv.b & self->qos_rx.link_disc_time.bits;
323 IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
324 self->qos_tx.link_disc_time.bits = final;
325 self->qos_rx.link_disc_time.bits = final;
327 return 0;
331 * Function irlap_param_max_turn_time (instance, param, get)
333 * Negotiate the maximum turnaround time. This is a type 1 parameter and
334 * will be negotiated independently for each station
337 static int irlap_param_max_turn_time(void *instance, param_t *param, int get)
339 struct irlap_cb *self = (struct irlap_cb *) instance;
341 ASSERT(self != NULL, return -1;);
342 ASSERT(self->magic == LAP_MAGIC, return -1;);
344 if (get)
345 param->pv.b = self->qos_rx.max_turn_time.bits;
346 else
347 self->qos_tx.max_turn_time.bits = param->pv.b;
349 return 0;
353 * Function irlap_param_data_size (instance, param, get)
355 * Negotiate the data size. This is a type 1 parameter and
356 * will be negotiated independently for each station
359 static int irlap_param_data_size(void *instance, param_t *param, int get)
361 struct irlap_cb *self = (struct irlap_cb *) instance;
363 ASSERT(self != NULL, return -1;);
364 ASSERT(self->magic == LAP_MAGIC, return -1;);
366 if (get)
367 param->pv.b = self->qos_rx.data_size.bits;
368 else
369 self->qos_tx.data_size.bits = param->pv.b;
371 return 0;
375 * Function irlap_param_window_size (instance, param, get)
377 * Negotiate the window size. This is a type 1 parameter and
378 * will be negotiated independently for each station
381 static int irlap_param_window_size(void *instance, param_t *param, int get)
383 struct irlap_cb *self = (struct irlap_cb *) instance;
385 ASSERT(self != NULL, return -1;);
386 ASSERT(self->magic == LAP_MAGIC, return -1;);
388 if (get)
389 param->pv.b = self->qos_rx.window_size.bits;
390 else
391 self->qos_tx.window_size.bits = param->pv.b;
393 return 0;
397 * Function irlap_param_additional_bofs (instance, param, get)
399 * Negotiate additional BOF characters. This is a type 1 parameter and
400 * will be negotiated independently for each station.
402 static int irlap_param_additional_bofs(void *instance, param_t *param, int get)
404 struct irlap_cb *self = (struct irlap_cb *) instance;
406 ASSERT(self != NULL, return -1;);
407 ASSERT(self->magic == LAP_MAGIC, return -1;);
409 if (get)
410 param->pv.b = self->qos_rx.additional_bofs.bits;
411 else
412 self->qos_tx.additional_bofs.bits = param->pv.b;
414 return 0;
418 * Function irlap_param_min_turn_time (instance, param, get)
420 * Negotiate the minimum turn around time. This is a type 1 parameter and
421 * will be negotiated independently for each station
423 static int irlap_param_min_turn_time(void *instance, param_t *param, int get)
425 struct irlap_cb *self = (struct irlap_cb *) instance;
427 ASSERT(self != NULL, return -1;);
428 ASSERT(self->magic == LAP_MAGIC, return -1;);
430 if (get)
431 param->pv.b = self->qos_rx.min_turn_time.bits;
432 else
433 self->qos_tx.min_turn_time.bits = param->pv.b;
435 return 0;
438 __u32 byte_value(__u8 byte, __u32 *array)
440 int index;
442 ASSERT(array != NULL, return -1;);
444 index = msb_index(byte);
446 return index_value(index, array);
450 * Function msb_index (word)
452 * Returns index to most significant bit (MSB) in word
455 int msb_index (__u16 word)
457 __u16 msb = 0x8000;
458 int index = 15; /* Current MSB */
460 while (msb) {
461 if (word & msb)
462 break; /* Found it! */
463 msb >>=1;
464 index--;
467 return index;
471 * Function value_index (value, array)
473 * Returns the index to the value in the specified array
475 int value_index(__u32 value, __u32 *array)
477 int i;
479 for (i=0;i<8;i++)
480 if (array[i] == value)
481 break;
482 return i;
486 * Function index_value (index, array)
488 * Returns value to index in array, easy!
491 __u32 index_value(int index, __u32 *array)
493 return array[index];
496 void irda_qos_bits_to_value(struct qos_info *qos)
498 int index;
500 ASSERT(qos != NULL, return;);
502 index = msb_index(qos->baud_rate.bits);
503 qos->baud_rate.value = baud_rates[index];
505 index = msb_index(qos->data_size.bits);
506 qos->data_size.value = data_size[index];
508 index = msb_index(qos->window_size.bits);
509 qos->window_size.value = index+1;
511 index = msb_index(qos->min_turn_time.bits);
512 qos->min_turn_time.value = min_turn_time[index];
514 index = msb_index(qos->max_turn_time.bits);
515 qos->max_turn_time.value = max_turn_time[index];
517 index = msb_index(qos->link_disc_time.bits);
518 qos->link_disc_time.value = link_disc_time[index];
520 index = msb_index(qos->additional_bofs.bits);
521 qos->additional_bofs.value = add_bofs[index];
523 #ifdef CONFIG_IRDA_COMPRESSION
524 index = msb_index(qos->compression.bits);
525 if (index >= 0)
526 qos->compression.value = compression[index];
527 else
528 qos->compression.value = 0;
529 #endif