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