Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-drm-fsl-dcu.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/sched.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         struct tty_struct *tty;
103         unsigned long flags;
104         struct sk_buff *skb;
105         int count;
106
107         IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
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, skb_tailroom(skb),
138                                   &ircomm_param_info);
139         if (count < 0) {
140                 IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
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", __FUNCTION__ , 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  */
165 static 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", __FUNCTION__ );
184                 return -1;
185         }
186         IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ ,
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", __FUNCTION__ ,
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  */
232 static 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", __FUNCTION__ ,
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  */
256 static 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", __FUNCTION__ );
265         } else {
266                 IRDA_DEBUG(0, "%s(), port-name=%s\n", __FUNCTION__ , 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  */
279 static 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", __FUNCTION__ , 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  */
302 static 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  */
324 static 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", __FUNCTION__ , (__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  */
348 static 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", __FUNCTION__ ,
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  */
375 static 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", __FUNCTION__ ,
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  */
402 static int ircomm_param_line_status(void *instance, irda_param_t *param,
403                                     int get)
404 {
405         IRDA_DEBUG(2, "%s(), not impl.\n", __FUNCTION__ );
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  */
416 static 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  */
461 static 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", __FUNCTION__ , (__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", __FUNCTION__ );
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  */
493 static 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 lenght 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