linux/net/irda/ircomm/ircomm_param.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      ircomm_param.c
   4 * Version:       1.0
   5 * Description:   Parameter handling for the IrCOMM protocol
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Mon Jun  7 10:25:11 1999
   9 * Modified at:   Sun Jan 30 14:32:03 2000
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 *
  12 *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  13 *
  14 *     This program is free software; you can redistribute it and/or
  15 *     modify it under the terms of the GNU General Public License as
  16 *     published by the Free Software Foundation; either version 2 of
  17 *     the License, or (at your option) any later version.
  18 *
  19 *     This program is distributed in the hope that it will be useful,
  20 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22 *     GNU General Public License for more details.
  23 *
  24 *     You should have received a copy of the GNU General Public License
  25 *     along with this program; if not, see <http://www.gnu.org/licenses/>.
  26 *
  27 ********************************************************************/
  28
  29#include <linux/gfp.h>
  30#include <linux/workqueue.h>
  31#include <linux/interrupt.h>
  32
  33#include <net/irda/irda.h>
  34#include <net/irda/parameters.h>
  35
  36#include <net/irda/ircomm_core.h>
  37#include <net/irda/ircomm_tty_attach.h>
  38#include <net/irda/ircomm_tty.h>
  39
  40#include <net/irda/ircomm_param.h>
  41
  42static int ircomm_param_service_type(void *instance, irda_param_t *param,
  43                                     int get);
  44static int ircomm_param_port_type(void *instance, irda_param_t *param,
  45                                  int get);
  46static int ircomm_param_port_name(void *instance, irda_param_t *param,
  47                                  int get);
  48static int ircomm_param_service_type(void *instance, irda_param_t *param,
  49                                     int get);
  50static int ircomm_param_data_rate(void *instance, irda_param_t *param,
  51                                  int get);
  52static int ircomm_param_data_format(void *instance, irda_param_t *param,
  53                                    int get);
  54static int ircomm_param_flow_control(void *instance, irda_param_t *param,
  55                                     int get);
  56static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
  57static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
  58static int ircomm_param_line_status(void *instance, irda_param_t *param,
  59                                    int get);
  60static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
  61static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
  62static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
  63
  64static const pi_minor_info_t pi_minor_call_table_common[] = {
  65        { ircomm_param_service_type, PV_INT_8_BITS },
  66        { ircomm_param_port_type,    PV_INT_8_BITS },
  67        { ircomm_param_port_name,    PV_STRING }
  68};
  69static const pi_minor_info_t pi_minor_call_table_non_raw[] = {
  70        { ircomm_param_data_rate,    PV_INT_32_BITS | PV_BIG_ENDIAN },
  71        { ircomm_param_data_format,  PV_INT_8_BITS },
  72        { ircomm_param_flow_control, PV_INT_8_BITS },
  73        { ircomm_param_xon_xoff,     PV_INT_16_BITS },
  74        { ircomm_param_enq_ack,      PV_INT_16_BITS },
  75        { ircomm_param_line_status,  PV_INT_8_BITS }
  76};
  77static const pi_minor_info_t pi_minor_call_table_9_wire[] = {
  78        { ircomm_param_dte,          PV_INT_8_BITS },
  79        { ircomm_param_dce,          PV_INT_8_BITS },
  80        { ircomm_param_poll,         PV_NO_VALUE },
  81};
  82
  83static const pi_major_info_t pi_major_call_table[] = {
  84        { pi_minor_call_table_common,  3 },
  85        { pi_minor_call_table_non_raw, 6 },
  86        { pi_minor_call_table_9_wire,  3 }
  87/*      { pi_minor_call_table_centronics }  */
  88};
  89
  90pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
  91
  92/*
  93 * Function ircomm_param_request (self, pi, flush)
  94 *
  95 *    Queue a parameter for the control channel
  96 *
  97 */
  98int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
  99{
 100        unsigned long flags;
 101        struct sk_buff *skb;
 102        int count;
 103
 104        IRDA_ASSERT(self != NULL, return -1;);
 105        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 106
 107        /* Make sure we don't send parameters for raw mode */
 108        if (self->service_type == IRCOMM_3_WIRE_RAW)
 109                return 0;
 110
 111        spin_lock_irqsave(&self->spinlock, flags);
 112
 113        skb = self->ctrl_skb;
 114        if (!skb) {
 115                skb = alloc_skb(256, GFP_ATOMIC);
 116                if (!skb) {
 117                        spin_unlock_irqrestore(&self->spinlock, flags);
 118                        return -ENOMEM;
 119                }
 120
 121                skb_reserve(skb, self->max_header_size);
 122                self->ctrl_skb = skb;
 123        }
 124        /*
 125         * Inserting is a little bit tricky since we don't know how much
 126         * room we will need. But this should hopefully work OK
 127         */
 128        count = irda_param_insert(self, pi, skb_tail_pointer(skb),
 129                                  skb_tailroom(skb), &ircomm_param_info);
 130        if (count < 0) {
 131                net_warn_ratelimited("%s(), no room for parameter!\n",
 132                                     __func__);
 133                spin_unlock_irqrestore(&self->spinlock, flags);
 134                return -1;
 135        }
 136        skb_put(skb, count);
 137        pr_debug("%s(), skb->len=%d\n", __func__, skb->len);
 138
 139        spin_unlock_irqrestore(&self->spinlock, flags);
 140
 141        if (flush) {
 142                /* ircomm_tty_do_softint will take care of the rest */
 143                schedule_work(&self->tqueue);
 144        }
 145
 146        return count;
 147}
 148
 149/*
 150 * Function ircomm_param_service_type (self, buf, len)
 151 *
 152 *    Handle service type, this function will both be called after the LM-IAS
 153 *    query and then the remote device sends its initial parameters
 154 *
 155 */
 156static int ircomm_param_service_type(void *instance, irda_param_t *param,
 157                                     int get)
 158{
 159        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 160        __u8 service_type = (__u8) param->pv.i;
 161
 162        IRDA_ASSERT(self != NULL, return -1;);
 163        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 164
 165        if (get) {
 166                param->pv.i = self->settings.service_type;
 167                return 0;
 168        }
 169
 170        /* Find all common service types */
 171        service_type &= self->service_type;
 172        if (!service_type) {
 173                pr_debug("%s(), No common service type to use!\n", __func__);
 174                return -1;
 175        }
 176        pr_debug("%s(), services in common=%02x\n", __func__ ,
 177                 service_type);
 178
 179        /*
 180         * Now choose a preferred service type of those available
 181         */
 182        if (service_type & IRCOMM_CENTRONICS)
 183                self->settings.service_type = IRCOMM_CENTRONICS;
 184        else if (service_type & IRCOMM_9_WIRE)
 185                self->settings.service_type = IRCOMM_9_WIRE;
 186        else if (service_type & IRCOMM_3_WIRE)
 187                self->settings.service_type = IRCOMM_3_WIRE;
 188        else if (service_type & IRCOMM_3_WIRE_RAW)
 189                self->settings.service_type = IRCOMM_3_WIRE_RAW;
 190
 191        pr_debug("%s(), resulting service type=0x%02x\n", __func__ ,
 192                 self->settings.service_type);
 193
 194        /*
 195         * Now the line is ready for some communication. Check if we are a
 196         * server, and send over some initial parameters.
 197         * Client do it in ircomm_tty_state_setup().
 198         * Note : we may get called from ircomm_tty_getvalue_confirm(),
 199         * therefore before we even have open any socket. And self->client
 200         * is initialised to TRUE only later. So, we check if the link is
 201         * really initialised. - Jean II
 202         */
 203        if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) &&
 204            (!self->client) &&
 205            (self->settings.service_type != IRCOMM_3_WIRE_RAW))
 206        {
 207                /* Init connection */
 208                ircomm_tty_send_initial_parameters(self);
 209                ircomm_tty_link_established(self);
 210        }
 211
 212        return 0;
 213}
 214
 215/*
 216 * Function ircomm_param_port_type (self, param)
 217 *
 218 *    The port type parameter tells if the devices are serial or parallel.
 219 *    Since we only advertise serial service, this parameter should only
 220 *    be equal to IRCOMM_SERIAL.
 221 */
 222static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
 223{
 224        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 225
 226        IRDA_ASSERT(self != NULL, return -1;);
 227        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 228
 229        if (get)
 230                param->pv.i = IRCOMM_SERIAL;
 231        else {
 232                self->settings.port_type = (__u8) param->pv.i;
 233
 234                pr_debug("%s(), port type=%d\n", __func__ ,
 235                         self->settings.port_type);
 236        }
 237        return 0;
 238}
 239
 240/*
 241 * Function ircomm_param_port_name (self, param)
 242 *
 243 *    Exchange port name
 244 *
 245 */
 246static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
 247{
 248        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 249
 250        IRDA_ASSERT(self != NULL, return -1;);
 251        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 252
 253        if (get) {
 254                pr_debug("%s(), not imp!\n", __func__);
 255        } else {
 256                pr_debug("%s(), port-name=%s\n", __func__ , param->pv.c);
 257                strncpy(self->settings.port_name, param->pv.c, 32);
 258        }
 259
 260        return 0;
 261}
 262
 263/*
 264 * Function ircomm_param_data_rate (self, param)
 265 *
 266 *    Exchange data rate to be used in this settings
 267 *
 268 */
 269static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
 270{
 271        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 272
 273        IRDA_ASSERT(self != NULL, return -1;);
 274        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 275
 276        if (get)
 277                param->pv.i = self->settings.data_rate;
 278        else
 279                self->settings.data_rate = param->pv.i;
 280
 281        pr_debug("%s(), data rate = %d\n", __func__ , param->pv.i);
 282
 283        return 0;
 284}
 285
 286/*
 287 * Function ircomm_param_data_format (self, param)
 288 *
 289 *    Exchange data format to be used in this settings
 290 *
 291 */
 292static int ircomm_param_data_format(void *instance, irda_param_t *param,
 293                                    int get)
 294{
 295        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 296
 297        IRDA_ASSERT(self != NULL, return -1;);
 298        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 299
 300        if (get)
 301                param->pv.i = self->settings.data_format;
 302        else
 303                self->settings.data_format = (__u8) param->pv.i;
 304
 305        return 0;
 306}
 307
 308/*
 309 * Function ircomm_param_flow_control (self, param)
 310 *
 311 *    Exchange flow control settings to be used in this settings
 312 *
 313 */
 314static int ircomm_param_flow_control(void *instance, irda_param_t *param,
 315                                     int get)
 316{
 317        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 318
 319        IRDA_ASSERT(self != NULL, return -1;);
 320        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 321
 322        if (get)
 323                param->pv.i = self->settings.flow_control;
 324        else
 325                self->settings.flow_control = (__u8) param->pv.i;
 326
 327        pr_debug("%s(), flow control = 0x%02x\n", __func__ , (__u8)param->pv.i);
 328
 329        return 0;
 330}
 331
 332/*
 333 * Function ircomm_param_xon_xoff (self, param)
 334 *
 335 *    Exchange XON/XOFF characters
 336 *
 337 */
 338static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
 339{
 340        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 341
 342        IRDA_ASSERT(self != NULL, return -1;);
 343        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 344
 345        if (get) {
 346                param->pv.i = self->settings.xonxoff[0];
 347                param->pv.i |= self->settings.xonxoff[1] << 8;
 348        } else {
 349                self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff;
 350                self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
 351        }
 352
 353        pr_debug("%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
 354                 param->pv.i & 0xff, param->pv.i >> 8);
 355
 356        return 0;
 357}
 358
 359/*
 360 * Function ircomm_param_enq_ack (self, param)
 361 *
 362 *    Exchange ENQ/ACK characters
 363 *
 364 */
 365static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
 366{
 367        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 368
 369        IRDA_ASSERT(self != NULL, return -1;);
 370        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 371
 372        if (get) {
 373                param->pv.i = self->settings.enqack[0];
 374                param->pv.i |= self->settings.enqack[1] << 8;
 375        } else {
 376                self->settings.enqack[0] = (__u16) param->pv.i & 0xff;
 377                self->settings.enqack[1] = (__u16) param->pv.i >> 8;
 378        }
 379
 380        pr_debug("%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
 381                 param->pv.i & 0xff, param->pv.i >> 8);
 382
 383        return 0;
 384}
 385
 386/*
 387 * Function ircomm_param_line_status (self, param)
 388 *
 389 *
 390 *
 391 */
 392static int ircomm_param_line_status(void *instance, irda_param_t *param,
 393                                    int get)
 394{
 395        pr_debug("%s(), not impl.\n", __func__);
 396
 397        return 0;
 398}
 399
 400/*
 401 * Function ircomm_param_dte (instance, param)
 402 *
 403 *    If we get here, there must be some sort of null-modem connection, and
 404 *    we are probably working in server mode as well.
 405 */
 406static int ircomm_param_dte(void *instance, irda_param_t *param, int get)
 407{
 408        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 409        __u8 dte;
 410
 411        IRDA_ASSERT(self != NULL, return -1;);
 412        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 413
 414        if (get)
 415                param->pv.i = self->settings.dte;
 416        else {
 417                dte = (__u8) param->pv.i;
 418
 419                self->settings.dce = 0;
 420
 421                if (dte & IRCOMM_DELTA_DTR)
 422                        self->settings.dce |= (IRCOMM_DELTA_DSR|
 423                                              IRCOMM_DELTA_RI |
 424                                              IRCOMM_DELTA_CD);
 425                if (dte & IRCOMM_DTR)
 426                        self->settings.dce |= (IRCOMM_DSR|
 427                                              IRCOMM_RI |
 428                                              IRCOMM_CD);
 429
 430                if (dte & IRCOMM_DELTA_RTS)
 431                        self->settings.dce |= IRCOMM_DELTA_CTS;
 432                if (dte & IRCOMM_RTS)
 433                        self->settings.dce |= IRCOMM_CTS;
 434
 435                /* Take appropriate actions */
 436                ircomm_tty_check_modem_status(self);
 437
 438                /* Null modem cable emulator */
 439                self->settings.null_modem = TRUE;
 440        }
 441
 442        return 0;
 443}
 444
 445/*
 446 * Function ircomm_param_dce (instance, param)
 447 *
 448 *
 449 *
 450 */
 451static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
 452{
 453        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 454        __u8 dce;
 455
 456        pr_debug("%s(), dce = 0x%02x\n", __func__ , (__u8)param->pv.i);
 457
 458        dce = (__u8) param->pv.i;
 459
 460        IRDA_ASSERT(self != NULL, return -1;);
 461        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 462
 463        self->settings.dce = dce;
 464
 465        /* Check if any of the settings have changed */
 466        if (dce & 0x0f) {
 467                if (dce & IRCOMM_DELTA_CTS) {
 468                        pr_debug("%s(), CTS\n", __func__);
 469                }
 470        }
 471
 472        ircomm_tty_check_modem_status(self);
 473
 474        return 0;
 475}
 476
 477/*
 478 * Function ircomm_param_poll (instance, param)
 479 *
 480 *    Called when the peer device is polling for the line settings
 481 *
 482 */
 483static int ircomm_param_poll(void *instance, irda_param_t *param, int get)
 484{
 485        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 486
 487        IRDA_ASSERT(self != NULL, return -1;);
 488        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 489
 490        /* Poll parameters are always of length 0 (just a signal) */
 491        if (!get) {
 492                /* Respond with DTE line settings */
 493                ircomm_param_request(self, IRCOMM_DTE, TRUE);
 494        }
 495        return 0;
 496}
 497
 498
 499
 500
 501
 502