Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ircomm_param.c
Go to the documentation of this file.
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 <[email protected]>
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 <[email protected]>
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>
40 #include <net/irda/ircomm_tty.h>
41 
42 #include <net/irda/ircomm_param.h>
43 
44 static int ircomm_param_service_type(void *instance, irda_param_t *param,
45  int get);
46 static int ircomm_param_port_type(void *instance, irda_param_t *param,
47  int get);
48 static int ircomm_param_port_name(void *instance, irda_param_t *param,
49  int get);
50 static int ircomm_param_service_type(void *instance, irda_param_t *param,
51  int get);
52 static int ircomm_param_data_rate(void *instance, irda_param_t *param,
53  int get);
54 static int ircomm_param_data_format(void *instance, irda_param_t *param,
55  int get);
56 static int ircomm_param_flow_control(void *instance, irda_param_t *param,
57  int get);
58 static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
59 static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
60 static int ircomm_param_line_status(void *instance, irda_param_t *param,
61  int get);
62 static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
63 static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
64 static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
65 
66 static 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 };
71 static 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 };
79 static 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 
85 static 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 
92 pi_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  */
100 int 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  */
160 static 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 */
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  */
227 static 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  */
251 static 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  */
274 static 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  */
297 static 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  */
319 static 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  */
343 static 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  */
370 static 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  */
397 static 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  */
411 static 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|
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 */
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  */
456 static 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 
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  */
488 static 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 */
499  }
500  return 0;
501 }
502 
503 
504 
505 
506