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