11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************************************************************
26819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filename:      qos.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version:       1.0
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description:   IrLAP QoS parameter negotiation
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Status:        Stable
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author:        Dag Brattli <dagb@cs.uit.no>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created at:    Tue Sep  9 00:00:26 1997
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified at:   Sun Jan 30 14:29:16 2000
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by:   Dag Brattli <dagb@cs.uit.no>
116819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
126819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     All Rights Reserved.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
156819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
166819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *     This program is free software; you can redistribute it and/or
176819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *     modify it under the terms of the GNU General Public License as
186819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *     published by the Free Software Foundation; either version 2 of
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     the License, or (at your option) any later version.
206819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     This program is distributed in the hope that it will be useful,
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     but WITHOUT ANY WARRANTY; without even the implied warranty of
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     GNU General Public License for more details.
256819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
266819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *     You should have received a copy of the GNU General Public License
27d37705092fb1bad8dade186451f3cca754a5d1d1Jeff Kirsher *     along with this program; if not, see <http://www.gnu.org/licenses/>.
286819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ********************************************************************/
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker#include <linux/export.h>
32bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/parameters.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/qos.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irlap.h>
39506e7beb7468c7cf56370d0a7a6afbec56653473Adrian Bunk#include <net/irda/irlap_frame.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Maximum values of the baud rate we negotiate with the other end.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Most often, you don't have to change that, because Linux-IrDA will
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use the maximum offered by the link layer, which usually works fine.
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In some very rare cases, you may want to limit it to lower speeds...
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sysctl_max_baud_rate = 16000000;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Maximum value of the lap disconnect timer we negotiate with the other end.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Most often, the value below represent the best compromise, but some user
5125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * may want to keep the LAP alive longer or shorter in case of link failure.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remember that the threshold time (early warning) is fixed to 3s...
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sysctl_max_noreply_time = 12;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Minimum turn time to be applied before transmitting to the peer.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nonzero values (usec) are used as lower limit to the per-connection
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mtt value which was announced by the other end during negotiation.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Might be helpful if the peer device provides too short mtt.
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Default is 10us which means using the unmodified value given by the
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * peer except if it's 0 (0 is likely a bug in the other stack).
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
639566042ef84fd2a282d00d3163074ec9b3f93a70Andi Kleenunsigned int sysctl_min_tx_turn_time = 10;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maximum data size to be used in transmission in payload of LAP frame.
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is a bit of confusion in the IrDA spec :
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The LAP spec defines the payload of a LAP frame (I field) to be
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40).
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * payload), that's only 2042 bytes. Oups !
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so adjust to 2042... I don't know if this bug applies only for 2048
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes frames or all negotiated frame sizes, but you can use the sysctl
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to play with this value anyway.
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jean II */
789566042ef84fd2a282d00d3163074ec9b3f93a70Andi Kleenunsigned int sysctl_max_tx_data_size = 2042;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maximum transmit window, i.e. number of LAP frames between turn-around.
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allow to override what the peer told us. Some peers are buggy and
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * don't always support what they tell us.
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jean II */
849566042ef84fd2a282d00d3163074ec9b3f93a70Andi Kleenunsigned int sysctl_max_tx_window = 7;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
876819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       int get);
896819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_max_turn_time(void *instance, irda_param_t *param,
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     int get);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irlap_param_data_size(void *instance, irda_param_t *param, int get);
926819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_window_size(void *instance, irda_param_t *param,
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   int get);
946819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       int get);
966819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_min_turn_time(void *instance, irda_param_t *param,
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     int get);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 irlap_requested_line_capacity(struct qos_info *qos);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 min_turn_times[]  = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
1046819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic __u32 baud_rates[]      = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   1152000, 4000000, 16000000 };           /* bps */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 data_sizes[]      = { 64, 128, 256, 512, 1024, 2048 };        /* bytes */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 add_bofs[]        = { 48, 24, 12, 5, 3, 2, 1, 0 };            /* bytes */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 max_turn_times[]  = { 500, 250, 100, 50 };                    /* ms */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 };         /* secs */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 max_line_capacities[10][4] = {
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       /* 500 ms     250 ms  100 ms  50 ms (max turn time) */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{    100,      0,      0,     0 }, /*     2400 bps */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{    400,      0,      0,     0 }, /*     9600 bps */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{    800,      0,      0,     0 }, /*    19200 bps */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{   1600,      0,      0,     0 }, /*    38400 bps */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{   2360,      0,      0,     0 }, /*    57600 bps */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{   4800,   2400,    960,   480 }, /*   115200 bps */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{  28800,  11520,   5760,  2880 }, /*   576000 bps */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{  57600,  28800,  11520,  5760 }, /*  1152000 bps */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 200000, 100000,  40000, 20000 }, /*  4000000 bps */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 800000, 400000, 160000, 80000 }, /* 16000000 bps */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic pi_minor_info_t pi_minor_call_table_type_0[] = {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 01 */{ irlap_param_baud_rate,       PV_INTEGER | PV_LITTLE_ENDIAN },
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS }
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic pi_minor_info_t pi_minor_call_table_type_1[] = {
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ NULL, 0 },
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 82 */{ irlap_param_max_turn_time,   PV_INT_8_BITS },
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 83 */{ irlap_param_data_size,       PV_INT_8_BITS },
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 84 */{ irlap_param_window_size,     PV_INT_8_BITS },
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS },
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 86 */{ irlap_param_min_turn_time,   PV_INT_8_BITS },
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic pi_major_info_t pi_major_call_table[] = {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ pi_minor_call_table_type_0, 9 },
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ pi_minor_call_table_type_1, 7 },
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------- LOCAL SUBROUTINES ---------------------- */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note : we start with a bunch of local subroutines.
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * As the compiler is "one pass", this is the only way to get them to
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inline properly...
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jean II
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function value_index (value, array, size)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns the index to the value in the specified array
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int value_index(__u32 value, __u32 *array, int size)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1686819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i < size; i++)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (array[i] == value)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function index_value (index, array)
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns value to index in array, easy!
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1816819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic inline __u32 index_value(int index, __u32 *array)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return array[index];
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function msb_index (word)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns index to most significant bit (MSB) in word
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1926819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int msb_index (__u16 word)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16 msb = 0x8000;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 15;   /* Current MSB */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for buggy peers.
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note : there is a small probability that it could be us, but I
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * would expect driver authors to catch that pretty early and be
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * able to check precisely what's going on. If a end user sees this,
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it's very likely the peer. - Jean II */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word == 0) {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
2040dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison			 __func__);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The only safe choice (we don't know the array size) */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		word = 0x1;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (msb) {
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (word & msb)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;   /* Found it! */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msb >>=1;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		index--;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return index;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function value_lower_bits (value, array)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns a bit field marking all possibility lower than value.
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	i;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16	mask = 0x1;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16	result = 0x0;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i < size; i++) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Add the current value to the bit field, shift mask */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result |= mask;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask <<= 1;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Finished ? */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (array[i] >= value)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send back a valid index */
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i >= size)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  i = size - 1;	/* Last item */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*field = result;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function value_highest_bit (value, array)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Returns a bit field marking the highest possibility lower than value.
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	i;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16	mask = 0x1;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16	result = 0x0;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i < size; i++) {
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Finished ? */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (array[i] <= value)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Shift mask */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask <<= 1;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set the current value to the bit field */
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result |= mask;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send back a valid index */
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i >= size)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  i = size - 1;	/* Last item */
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*field = result;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------- MAIN CALLS -------------------------- */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irda_qos_compute_intersection (qos, new)
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Compute the intersection of the old QoS capabilities with new ones
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(qos != NULL, return;);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(new != NULL, return;);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Apply */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->baud_rate.bits       &= new->baud_rate.bits;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->window_size.bits     &= new->window_size.bits;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->min_turn_time.bits   &= new->min_turn_time.bits;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->max_turn_time.bits   &= new->max_turn_time.bits;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->data_size.bits       &= new->data_size.bits;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->link_disc_time.bits  &= new->link_disc_time.bits;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->additional_bofs.bits &= new->additional_bofs.bits;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_qos_bits_to_value(qos);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irda_init_max_qos_capabilies (qos)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    The purpose of this function is for layers and drivers to be able to
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    set the maximum QoS possible and then "and in" their own limitations
3016819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid irda_init_max_qos_capabilies(struct qos_info *qos)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3066819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	/*
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  These are the maximum supported values as specified on pages
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  39-43 in IrLAP
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Use sysctl to set some configurable values... */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set configured max speed */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10,
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     &qos->baud_rate.bits);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sysctl_max_baud_rate = index_value(i, baud_rates);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set configured max disc time */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8,
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     &qos->link_disc_time.bits);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sysctl_max_noreply_time = index_value(i, link_disc_times);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* LSB is first byte, MSB is second byte */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->baud_rate.bits    &= 0x03ff;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->window_size.bits     = 0x7f;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->min_turn_time.bits   = 0xff;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->max_turn_time.bits   = 0x0f;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->data_size.bits       = 0x3f;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->link_disc_time.bits &= 0xff;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->additional_bofs.bits = 0xff;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(irda_init_max_qos_capabilies);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_adjust_qos_settings (qos)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Adjust QoS settings in case some values are not possible to use because
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     of other settings
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void irlap_adjust_qos_settings(struct qos_info *qos)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u32 line_capacity;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3450dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison	IRDA_DEBUG(2, "%s()\n", __func__);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Make sure the mintt is sensible.
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Main culprit : Ericsson T39. - Jean II
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
3550dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison			 __func__, sysctl_min_tx_turn_time);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't really need bits, but easier this way */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      8, &qos->min_turn_time.bits);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sysctl_min_tx_turn_time = index_value(i, min_turn_times);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qos->min_turn_time.value = sysctl_min_tx_turn_time;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3646819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	/*
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Not allowed to use a max turn time less than 500 ms if the baudrate
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * is less than 115200
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3686819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	if ((qos->baud_rate.value < 115200) &&
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (qos->max_turn_time.value < 500))
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
3716819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		IRDA_DEBUG(0,
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   "%s(), adjusting max turn time from %d to 500 ms\n",
3730dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison			   __func__, qos->max_turn_time.value);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qos->max_turn_time.value = 500;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3766819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3786819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	 * The data size must be adjusted according to the baud rate and max
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * turn time
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = value_index(qos->data_size.value, data_sizes, 6);
3826819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						qos->max_turn_time.value);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((qos->data_size.value > line_capacity) && (index > 0)) {
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qos->data_size.value = data_sizes[index--];
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
3890dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison			   __func__, qos->data_size.value);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* Use method described in section 6.6.11 of IrLAP */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (irlap_requested_line_capacity(qos) > line_capacity) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_ASSERT(index != 0, return;);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Must be able to send at least one frame */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qos->window_size.value > 1) {
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qos->window_size.value--;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			IRDA_DEBUG(2, "%s(), reducing window size to %d\n",
3990dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison				   __func__, qos->window_size.value);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (index > 1) {
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qos->data_size.value = data_sizes[index--];
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
4030dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison				   __func__, qos->data_size.value);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			IRDA_WARNING("%s(), nothing more we can do!\n",
4060dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison				     __func__);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Fix tx data size according to user limits - Jean II
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qos->data_size.value > sysctl_max_tx_data_size)
41425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* Allow non discrete adjustement to avoid losing capacity */
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qos->data_size.value = sysctl_max_tx_data_size;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Override Tx window if user request it. - Jean II
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qos->window_size.value > sysctl_max_tx_window)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qos->window_size.value = sysctl_max_tx_window;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_negotiate (qos_device, qos_session, skb)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate QoS values, not really that much negotiation :-)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    We just set the QoS capabilities for the peer station
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4306819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakiint irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4336819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
4346819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	ret = irda_param_extract_all(self, skb->data, skb->len,
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &irlap_param_info);
4366819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Convert the negotiated bits to values */
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_qos_bits_to_value(&self->qos_tx);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irda_qos_bits_to_value(&self->qos_rx);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irlap_adjust_qos_settings(&self->qos_tx);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4436819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.baud_rate.value);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.data_size.value);
4476819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.window_size.value);
4496819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	IRDA_DEBUG(2, "Setting XBOFS to %d\n",
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.additional_bofs.value);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.max_turn_time.value);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.min_turn_time.value);
4556819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   self->qos_tx.link_disc_time.value);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_insert_negotiation_params (qos, fp)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Insert QoS negotiaion pararameters into frame
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4666819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakiint irlap_insert_qos_negotiation_params(struct irlap_cb *self,
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					struct sk_buff *skb)
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert data rate */
47227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb),
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert max turnaround time */
47927a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb),
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert data size */
48627a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb),
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert window size */
49327a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb),
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert additional BOFs */
50027a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb),
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert minimum turnaround time */
50727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb),
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Insert link disconnect/threshold time */
51427a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb),
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_tailroom(skb), &irlap_param_info);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, ret);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_baud_rate (instance, param, get)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate data-rate
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16 final;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get) {
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.baud_rate.bits;
5406819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n",
5410dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison			   __func__, param->pv.i);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5436819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		/*
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  Stations must agree on baud rate, so calculate
5456819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		 *  intersection
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", (__u16) param->pv.i);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.baud_rate.bits = final;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_rx.baud_rate.bits = final;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_link_disconnect (instance, param, get)
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5616819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki *    Negotiate link disconnect/threshold time.
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5646819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_link_disconnect(void *instance, irda_param_t *param,
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       int get)
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u16 final;
5686819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
5706819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
5736819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.link_disc_time.bits;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
5776819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		/*
5786819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki		 *  Stations must agree on link disconnect/threshold
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  time.
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "LINK_DISC: %02x\n", (__u8) param->pv.i);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.link_disc_time.bits = final;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_rx.link_disc_time.bits = final;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_max_turn_time (instance, param, get)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate the maximum turnaround time. This is a type 1 parameter and
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will be negotiated independently for each station
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5986819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_max_turn_time(void *instance, irda_param_t *param,
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     int get)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
6026819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
6056819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.max_turn_time.bits;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.max_turn_time.bits = (__u8) param->pv.i;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_data_size (instance, param, get)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate the data size. This is a type 1 parameter and
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will be negotiated independently for each station
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irlap_param_data_size(void *instance, irda_param_t *param, int get)
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
6246819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
6276819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.data_size.bits;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.data_size.bits = (__u8) param->pv.i;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_window_size (instance, param, get)
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate the window size. This is a type 1 parameter and
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will be negotiated independently for each station
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6436819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_window_size(void *instance, irda_param_t *param,
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   int get)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
6476819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
6506819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.window_size.bits;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.window_size.bits = (__u8) param->pv.i;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_additional_bofs (instance, param, get)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate additional BOF characters. This is a type 1 parameter and
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will be negotiated independently for each station.
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
6686819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
6716819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.additional_bofs.bits;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.additional_bofs.bits = (__u8) param->pv.i;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_param_min_turn_time (instance, param, get)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Negotiate the minimum turn around time. This is a type 1 parameter and
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    will be negotiated independently for each station
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6866819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int irlap_param_min_turn_time(void *instance, irda_param_t *param,
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     int get)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irlap_cb *self = (struct irlap_cb *) instance;
6906819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self != NULL, return -1;);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
6936819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get)
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		param->pv.i = self->qos_rx.min_turn_time.bits;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		self->qos_tx.min_turn_time.bits = (__u8) param->pv.i;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time)
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Calculate the maximum line capacity
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u32 line_capacity;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i,j;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n",
7140dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison		   __func__, speed, max_turn_time);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = value_index(speed, baud_rates, 10);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	j = value_index(max_turn_time, max_turn_times, 4);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(((i >=0) && (i <10)), return 0;);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(((j >=0) && (j <4)), return 0;);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	line_capacity = max_line_capacities[i][j];
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7246819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki	IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n",
7250dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison		   __func__, line_capacity);
7266819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return line_capacity;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u32 irlap_requested_line_capacity(struct qos_info *qos)
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u32 line_capacity;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	line_capacity = qos->window_size.value *
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(qos->data_size.value + 6 + qos->additional_bofs.value) +
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irlap_min_turn_time_in_bytes(qos->baud_rate.value,
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     qos->min_turn_time.value);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_DEBUG(2, "%s(), requested line capacity=%d\n",
7410dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison		   __func__, line_capacity);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return line_capacity;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid irda_qos_bits_to_value(struct qos_info *qos)
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IRDA_ASSERT(qos != NULL, return;);
7526819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->baud_rate.bits);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->baud_rate.value = baud_rates[index];
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->data_size.bits);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->data_size.value = data_sizes[index];
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->window_size.bits);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->window_size.value = index+1;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->min_turn_time.bits);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->min_turn_time.value = min_turn_times[index];
7646819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->max_turn_time.bits);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->max_turn_time.value = max_turn_times[index];
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->link_disc_time.bits);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->link_disc_time.value = link_disc_times[index];
7706819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = msb_index(qos->additional_bofs.bits);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qos->additional_bofs.value = add_bofs[index];
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(irda_qos_bits_to_value);
775