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