PageRenderTime 73ms CodeModel.GetById 15ms app.highlight 53ms RepoModel.GetById 2ms app.codeStats 0ms

/net/irda/ircomm/ircomm_param.c

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