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