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