]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/irda/ircomm/ircomm_param.c
Merge branch 'for-3.10' of git://linux-nfs.org/~bfields/linux
[karo-tx-linux.git] / net / irda / ircomm / ircomm_param.c
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
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 */
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  */
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|
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  */
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
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  */
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 */
498                 ircomm_param_request(self, IRCOMM_DTE, TRUE);
499         }
500         return 0;
501 }
502
503
504
505
506