patch-2.1.132 linux/net/irda/qos.c
Next file: linux/net/irda/timer.c
Previous file: linux/net/irda/irttp.c
Back to the patch index
Back to the overall index
- Lines: 449
- Date:
Thu Dec 17 09:01:03 1998
- Orig file:
v2.1.131/linux/net/irda/qos.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.131/linux/net/irda/qos.c linux/net/irda/qos.c
@@ -0,0 +1,448 @@
+/*********************************************************************
+ *
+ * Filename: qos.c
+ * Version: 0.1
+ * Description: IrLAP QoS negotiation
+ * Status: Experimental.
+ * Author: Dag Brattli <dagb@cs.uit.no>
+ * Created at: Tue Sep 9 00:00:26 1997
+ * Modified at: Sat Dec 12 12:21:42 1998
+ * Modified by: Dag Brattli <dagb@cs.uit.no>
+ *
+ * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Neither Dag Brattli nor University of Tromsų admit liability nor
+ * provide warranty for any of this software. This material is
+ * provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <asm/byteorder.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/qos.h>
+#include <net/irda/irlap.h>
+#ifdef CONFIG_IRDA_COMPRESSION
+#include <net/irda/irlap_comp.h>
+#include "../../drivers/net/zlib.h"
+
+#define CI_BZIP2 27 /* Random pick */
+#endif
+
+int min_turn_time[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 };
+int baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, 1152000,
+ 4000000 };
+int data_size[] = { 64, 128, 256, 512, 1024, 2048 };
+int add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 };
+int max_turn_time[] = { 500, 250, 100, 50 };
+int link_disc_time[] = { 3, 8, 12, 16, 20, 25, 30, 40 };
+
+#ifdef CONFIG_IRDA_COMPRESSION
+int compression[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
+#endif
+/*
+ * Function irda_qos_compute_intersection (qos, new)
+ *
+ * Compute the intersection of the old QoS capabilites with new ones
+ *
+ */
+void irda_qos_compute_intersection( struct qos_info *qos, struct qos_info *new)
+{
+ ASSERT( qos != NULL, return;);
+ ASSERT( new != NULL, return;);
+
+ /* Apply */
+ qos->baud_rate.bits &= new->baud_rate.bits;
+ qos->window_size.bits &= new->window_size.bits;
+ qos->min_turn_time.bits &= new->min_turn_time.bits;
+ qos->max_turn_time.bits &= new->max_turn_time.bits;
+ qos->data_size.bits &= new->data_size.bits;
+ qos->link_disc_time.bits &= new->link_disc_time.bits;
+ qos->additional_bofs.bits &= new->additional_bofs.bits;
+
+#ifdef CONFIG_IRDA_COMPRESSION
+ qos->compression.bits &= new->compression.bits;
+#endif
+
+ irda_qos_bits_to_value( qos);
+}
+
+/*
+ * Function irda_init_max_qos_capabilies (qos)
+ *
+ * The purpose of this function is for layers and drivers to be able to
+ * set the maximum QoS possible and then "and in" their own limitations
+ *
+ */
+void irda_init_max_qos_capabilies( struct qos_info *qos)
+{
+ /*
+ * These are the maximum supported values as specified on pages
+ * 39-43 in IrLAP
+ */
+
+ /* LSB is first byte, MSB is second byte */
+ qos->baud_rate.bits = 0x01ff;
+
+ qos->window_size.bits = 0x7f;
+ qos->min_turn_time.bits = 0xff;
+ qos->max_turn_time.bits = 0x0f;
+ qos->data_size.bits = 0x3f;
+ qos->link_disc_time.bits = 0xff;
+ qos->additional_bofs.bits = 0xff;
+
+#ifdef CONFIG_IRDA_COMPRESSION
+ qos->compression.bits = 0x03;
+#endif
+}
+
+/*
+ * Function irlap_negotiate (qos_device, qos_session, skb)
+ *
+ * Negotiate QoS values, not really that much negotiation :-)
+ * We just set the QoS capabilities for the peer station
+ *
+ */
+void irda_qos_negotiate( struct qos_info *qos_rx, struct qos_info *qos_tx,
+ struct sk_buff *skb)
+{
+ int n=0;
+#ifdef CONFIG_IRDA_COMPRESSION
+ int comp_seen = FALSE;
+#endif
+ __u8 length;
+ __u8 *frame;
+ __u8 final_byte;
+ __u8 code;
+ __u8 byte;
+ __u16 final_word;
+ __u16_host_order word;
+
+ ASSERT( qos_tx != NULL, return;);
+ ASSERT( qos_rx != NULL, return;);
+ ASSERT( skb != NULL, return;);
+
+ frame = skb->data;
+
+ while( n < skb->len-2) {
+ code = frame[n++];
+ /* Length */
+ length = frame[n++];
+
+ /*
+ * Get the value, since baud_rate may need two bytes, we
+ * Just use word size all the time
+ */
+ switch( length) {
+ case 1:
+ byte = frame[n++];
+ word.word = byte; /* To make things a little easier */
+ break;
+ case 2:
+#ifdef __LITTLE_ENDIAN
+ word.byte[0] = frame[n++];
+ word.byte[1] = frame[n++];
+#else ifdef __BIG_ENDIAN
+ word.byte[1] = frame[n++];
+ word.byte[0] = frame[n++];
+#endif
+ byte = 0;
+ break;
+ default:
+ DEBUG( 0, __FUNCTION__ "Error\n");
+ word.word = byte = 0;
+ n += length;
+
+ break;
+ }
+
+ switch( code) {
+ case PI_BAUD_RATE:
+ /*
+ * Stations must agree on baud rate, so calculate
+ * intersection
+ */
+ DEBUG( 4, "Requested BAUD_RATE: 0x%04x\n", word.word);
+ final_word = word.word & qos_rx->baud_rate.bits;
+ DEBUG( 4, "Final BAUD_RATE: 0x%04x\n", final_word);
+ qos_tx->baud_rate.bits = final_word;
+ qos_rx->baud_rate.bits = final_word;
+ break;
+ case PI_MAX_TURN_TIME:
+ /*
+ * Negotiated independently for each station
+ */
+ DEBUG( 4, "MAX_TURN_TIME: %02x\n", byte);
+ qos_tx->max_turn_time.bits = byte;
+ break;
+ case PI_DATA_SIZE:
+ /*
+ * Negotiated independently for each station
+ */
+ DEBUG( 4, "DATA_SIZE: %02x\n", byte);
+ qos_tx->data_size.bits = byte;
+ break;
+ case PI_WINDOW_SIZE:
+ /*
+ * Negotiated independently for each station
+ */
+ qos_tx->window_size.bits = byte;
+ break;
+ case PI_ADD_BOFS:
+ /*
+ * Negotiated independently for each station
+ */
+ DEBUG( 4, "ADD_BOFS: %02x\n", byte);
+ qos_tx->additional_bofs.bits = byte;
+ break;
+ case PI_MIN_TURN_TIME:
+ DEBUG( 4, "MIN_TURN_TIME: %02x\n", byte);
+ qos_tx->min_turn_time.bits = byte;
+ break;
+ case PI_LINK_DISC:
+ /*
+ * Stations must agree on link disconnect/threshold
+ * time.
+ */
+ DEBUG( 4, "LINK_DISC: %02x\n", byte);
+
+ final_byte = byte & qos_rx->link_disc_time.bits;
+ DEBUG( 4, "Final LINK_DISC: %02x\n", final_byte);
+ qos_tx->link_disc_time.bits = final_byte;
+ qos_rx->link_disc_time.bits = final_byte;
+ break;
+#ifdef CONFIG_IRDA_COMPRESSION
+ case PI_COMPRESSION:
+ final_byte = byte & qos_rx->compression.bits;
+ qos_rx->compression.bits = byte;
+ qos_tx->compression.bits = byte;
+ comp_seen = TRUE;
+ break;
+#endif
+ default:
+ DEBUG( 0, __FUNCTION__ "(), Unknown value\n");
+ break;
+ }
+ }
+#ifdef CONFIG_IRDA_COMPRESSION
+ if ( !comp_seen) {
+ DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
+ qos_tx->compression.bits = 0x00;
+ qos_rx->compression.bits = 0x00;
+ }
+#endif
+ /* Convert the negotiated bits to values */
+ irda_qos_bits_to_value( qos_tx);
+ irda_qos_bits_to_value( qos_rx);
+
+ DEBUG( 4, "Setting BAUD_RATE to %d bps.\n",
+ qos_tx->baud_rate.value);
+ DEBUG( 4, "Setting DATA_SIZE to %d bytes\n",
+ qos_tx->data_size.value);
+ DEBUG( 4, "Setting WINDOW_SIZE to %d\n",
+ qos_tx->window_size.value);
+ DEBUG( 4, "Setting XBOFS to %d\n",
+ qos_tx->additional_bofs.value);
+ DEBUG( 4, "Setting MAX_TURN_TIME to %d ms.\n",
+ qos_tx->max_turn_time.value);
+ DEBUG( 4, "Setting MIN_TURN_TIME to %d usecs.\n",
+ qos_tx->min_turn_time.value);
+ DEBUG( 4, "Setting LINK_DISC to %d secs.\n",
+ qos_tx->link_disc_time.value);
+#ifdef CONFIG_IRDA_COMPRESSION
+ DEBUG( 4, "Setting COMPRESSION to %d\n",
+ qos_tx->compression.value);
+#endif
+
+}
+
+/*
+ * Function irlap_insert_negotiation_params (qos, fp)
+ *
+ * Insert QoS negotiaion pararameters into frame
+ *
+ */
+int irda_insert_qos_negotiation_params( struct qos_info *qos, __u8 *frame)
+{
+ int n;
+ __u16_host_order word;
+
+ ASSERT( qos != NULL, return 0;);
+ ASSERT( frame != NULL, return 0;);
+
+ n = 0;
+
+ /* Set baud rate */
+ if (qos->baud_rate.bits < 256) {
+ frame[n++] = PI_BAUD_RATE;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->baud_rate.bits;
+ } else {
+ frame[n++] = PI_BAUD_RATE;
+ frame[n++] = 0x02; /* length 2 */
+
+ /*
+ * qos->baud_rate.bits is in host byte order, so make sure
+ * we transmit it in little endian format
+ */
+ word.word = qos->baud_rate.bits;
+#ifdef __LITTLE_ENDIAN
+ frame[n++] = word.byte[0]; /* LSB */
+ frame[n++] = word.byte[1]; /* MSB */
+#else ifdef __BIG_ENDIAN
+ frame[n++] = word.byte[1]; /* LSB */
+ frame[n++] = word.byte[0]; /* MSB */
+#endif
+ }
+
+ /* Set Maximum Turn Around Time */
+ frame[n++] = PI_MAX_TURN_TIME;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->max_turn_time.bits;
+
+ /* Set data size */
+ frame[n++] = PI_DATA_SIZE;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->data_size.bits;
+
+ /* Set window size */
+ frame[n++] = PI_WINDOW_SIZE;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->window_size.bits;
+
+ /* Set additional BOFs */
+ frame[n++] = PI_ADD_BOFS;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->additional_bofs.bits;
+
+ /* Set minimum turn around time */
+ frame[n++] = PI_MIN_TURN_TIME;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->min_turn_time.bits;
+
+ /* Set Link Disconnect/Threshold Time */
+ frame[n++] = PI_LINK_DISC;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->link_disc_time.bits;
+#ifdef CONFIG_IRDA_COMPRESSION
+ /* Set compression bits*/
+ if ( qos->compression.bits) {
+ DEBUG( 4, __FUNCTION__ "(), inserting compresion bits\n");
+ frame[n++] = PI_COMPRESSION;
+ frame[n++] = 0x01; /* length 1 */
+ frame[n++] = qos->compression.bits;
+ }
+#endif
+ return n;
+}
+
+int byte_value( __u8 byte, int *array)
+{
+ int index;
+
+ ASSERT( array != NULL, return -1;);
+
+ index = msb_index( byte);
+ return index_value( index, array);
+}
+
+
+/* __u8 value_byte( int value, int *array) */
+/* { */
+/* int index; */
+/* __u8 byte; */
+
+/* index = value_index( value, array); */
+
+/* byte = */
+/* } */
+
+/*
+ * Function msb_index (word)
+ *
+ * Returns index to most significant bit (MSB) in word
+ *
+ */
+int msb_index ( __u16 word)
+{
+ __u16 msb = 0x8000;
+ int index = 15; /* Current MSB */
+
+ while( msb) {
+ if ( word & msb)
+ break; /* Found it! */
+ msb >>=1;
+ index--;
+ }
+
+ return index;
+}
+
+/*
+ * Function value_index (value, array)
+ *
+ * Returns the index to the value in the specified array
+ */
+int value_index( int value, int *array)
+{
+ int i;
+
+ for( i=0;i<8;i++)
+ if ( array[i] == value)
+ break;
+ return i;
+}
+
+/*
+ * Function index_value (index, array)
+ *
+ * Returns value to index in array, easy!
+ *
+ */
+int index_value( int index, int *array)
+{
+ return array[index];
+}
+
+void irda_qos_bits_to_value( struct qos_info *qos)
+{
+ int index;
+
+ ASSERT( qos != NULL, return;);
+
+ index = msb_index( qos->baud_rate.bits);
+ qos->baud_rate.value = baud_rates[index];
+
+ index = msb_index( qos->data_size.bits);
+ qos->data_size.value = data_size[index];
+
+ index = msb_index( qos->window_size.bits);
+ qos->window_size.value = index+1;
+
+ index = msb_index( qos->min_turn_time.bits);
+ qos->min_turn_time.value = min_turn_time[index];
+
+ index = msb_index( qos->max_turn_time.bits);
+ qos->max_turn_time.value = max_turn_time[index];
+
+ index = msb_index( qos->link_disc_time.bits);
+ qos->link_disc_time.value = link_disc_time[index];
+
+ index = msb_index( qos->additional_bofs.bits);
+ qos->additional_bofs.value = add_bofs[index];
+
+#ifdef CONFIG_IRDA_COMPRESSION
+ index = msb_index( qos->compression.bits);
+ if ( index >= 0)
+ qos->compression.value = compression[index];
+ else
+ qos->compression.value = 0;
+#endif
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov