Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc2 501 lines 14 kB view raw
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