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  */
ircomm_param_request(struct ircomm_tty_cb * self,__u8 pi,int flush)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", __func__ );
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_pointer(skb),
138 				  skb_tailroom(skb), &ircomm_param_info);
139 	if (count < 0) {
140 		IRDA_WARNING("%s(), no room for parameter!\n", __func__);
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", __func__ , 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  */
ircomm_param_service_type(void * instance,irda_param_t * param,int get)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", __func__ );
184 		return -1;
185 	}
186 	IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ ,
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", __func__ ,
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  */
ircomm_param_port_type(void * instance,irda_param_t * param,int get)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", __func__ ,
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  */
ircomm_param_port_name(void * instance,irda_param_t * param,int get)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", __func__ );
265 	} else {
266 		IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , 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  */
ircomm_param_data_rate(void * instance,irda_param_t * param,int get)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", __func__ , 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  */
ircomm_param_data_format(void * instance,irda_param_t * param,int get)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  */
ircomm_param_flow_control(void * instance,irda_param_t * param,int get)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", __func__ , (__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  */
ircomm_param_xon_xoff(void * instance,irda_param_t * param,int get)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", __func__ ,
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  */
ircomm_param_enq_ack(void * instance,irda_param_t * param,int get)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", __func__ ,
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  */
ircomm_param_line_status(void * instance,irda_param_t * param,int get)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", __func__ );
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  */
ircomm_param_dte(void * instance,irda_param_t * param,int get)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  */
ircomm_param_dce(void * instance,irda_param_t * param,int get)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", __func__ , (__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", __func__ );
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  */
ircomm_param_poll(void * instance,irda_param_t * param,int get)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 length 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 
512