2.2.0-final
[davej-history.git] / net / irda / irlpt / irlpt_cli.c
blobc98985cfbfe081efd7a9b8744506d029c137a645
1 /*********************************************************************
3 * Filename: irlpt.c
4 * Version:
5 * Description:
6 * Status: Experimental.
7 * Author: Thomas Davis, <ratbert@radiks.net>
8 * Created at: Sat Feb 21 18:54:38 1998
9 * Modified at: Sun Mar 8 23:44:19 1998
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: irlan.c
13 * Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
14 * Copyright (c) 1998, Dag Brattli, <dagb@cs.uit.no>
15 * All Rights Reserved.
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
22 * I, Thomas Davis, provide no warranty for any of this software.
23 * This material is provided "AS-IS" and at no charge.
25 ********************************************************************/
27 #include <net/irda/irlap.h>
28 #include <net/irda/irttp.h>
29 #include <net/irda/irlmp.h>
30 #include <net/irda/irias_object.h>
31 #include <net/irda/iriap.h>
32 #include <net/irda/irlpt_common.h>
33 #include <net/irda/irlpt_cli.h>
34 #include <net/irda/irlpt_cli_fsm.h>
35 #include <net/irda/timer.h>
36 #include <net/irda/irda.h>
38 #include <linux/config.h>
39 #include <linux/init.h>
40 #include <linux/module.h>
42 #include <asm/uaccess.h>
43 #include <linux/miscdevice.h>
44 #include <linux/proc_fs.h>
46 int irlpt_client_init(void);
47 static void irlpt_client_cleanup(void);
48 static void irlpt_client_close(struct irlpt_cb *self);
50 static void irlpt_client_discovery_indication( DISCOVERY *);
52 static void irlpt_client_connect_confirm( void *instance, void *sap,
53 struct qos_info *qos,
54 int max_seg_size,
55 struct sk_buff *skb);
56 static void irlpt_client_disconnect_indication( void *instance, void *sap,
57 LM_REASON reason,
58 struct sk_buff *userdata);
60 #if 0
61 static char *rcsid = "$Id: irlpt_client.c,v 1.10 1998/11/10 22:50:57 dagb Exp $";
62 #endif
63 static char *version = "IrLPT, $Revision: 1.10 $/$Date: 1998/11/10 22:50:57 $ (Thomas Davis)";
65 struct file_operations client_fops = {
66 irlpt_seek, /* seek */
67 NULL, /* read_irlpt (server) */
68 irlpt_write, /* write */
69 NULL, /* readdir */
70 NULL, /* poll */
71 NULL, /* ioctl */
72 NULL, /* mmap */
73 irlpt_open, /* open */
74 NULL, /* flush */
75 irlpt_close, /* release */
76 NULL, /* fsync */
77 NULL, /* fasync */
78 NULL, /* check_media_change */
79 NULL, /* revalidate */
80 NULL, /* lock */
83 int irlpt_client_debug = 4;
85 extern char *irlptstate[];
87 #ifdef CONFIG_PROC_FS
90 * Function client_proc_read (buf, start, offset, len, unused)
93 static int irlpt_client_proc_read( char *buf, char **start, off_t offset,
94 int len, int unused)
96 struct irlpt_cb *self;
97 int index;
99 len = sprintf(buf, "%s\n\n", version);
101 self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
102 while( self) {
103 ASSERT( self != NULL, return len;);
104 ASSERT( self->magic == IRLPT_MAGIC, return len;);
106 len += sprintf(buf+len, "ifname: %s\n", self->ifname);
107 len += sprintf(buf+len, "minor: %d\n", self->ir_dev.minor);
109 switch ( self->servicetype) {
110 case IRLPT_UNKNOWN:
111 index = 0;
112 break;
113 case IRLPT_THREE_WIRE_RAW:
114 index = 1;
115 break;
116 case IRLPT_THREE_WIRE:
117 index = 2;
118 break;
119 case IRLPT_NINE_WIRE:
120 index = 3;
121 break;
122 case IRLPT_CENTRONICS:
123 index = 4;
124 break;
125 case IRLPT_SERVER_MODE:
126 index = 5;
127 break;
128 default:
129 index = 0;
130 break;
133 len += sprintf(buf+len, "service_type: %s\n",
134 irlpt_service_type[index]);
135 len += sprintf(buf+len, "port_type: %s\n",
136 irlpt_port_type[ self->porttype]);
137 len += sprintf(buf+len, "daddr: 0x%08x\n", self->daddr);
138 len += sprintf(buf+len, "fsm_state: %s\n",
139 irlpt_client_fsm_state[self->state]);
140 len += sprintf(buf+len, "retries: %d\n", self->open_retries);
141 len += sprintf(buf+len, "dlsap: %d\n", self->dlsap_sel);
143 len += sprintf(buf+len, "count: %d\n", self->count);
144 len += sprintf(buf+len, "rx_queue: %d\n",
145 skb_queue_len(&self->rx_queue));
146 len += sprintf(buf+len, "\n\n");
148 self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
151 return len;
154 struct proc_dir_entry proc_irlpt_client = {
155 0, 12, "irlpt_client",
156 S_IFREG | S_IRUGO, 1, 0, 0,
157 0, NULL /* ops -- default to array */,
158 &irlpt_client_proc_read /* get_info */,
161 extern struct proc_dir_entry proc_irda;
163 #endif /* CONFIG_PROC_FS */
166 * Function irlpt_init (dev)
168 * Initializes the irlpt control structure
171 __initfunc(int irlpt_client_init(void))
173 DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
175 printk( KERN_INFO "%s\n", version);
177 irlpt_clients = hashbin_new( HB_LOCAL);
178 if ( irlpt_clients == NULL) {
179 printk( KERN_WARNING "IrLPT: Can't allocate hashbin!\n");
180 return -ENOMEM;
183 irlmp_register_layer( S_PRINTER, CLIENT, TRUE,
184 irlpt_client_discovery_indication);
186 #ifdef CONFIG_PROC_FS
187 proc_register( &proc_irda, &proc_irlpt_client);
188 #endif /* CONFIG_PROC_FS */
190 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
192 return 0;
196 #ifdef MODULE
198 * Function irlpt_cleanup (void)
203 static void irlpt_client_cleanup(void)
205 DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
207 irlmp_unregister_layer( S_PRINTER, CLIENT);
210 * Delete hashbin and close all irlan client instances in it
212 hashbin_delete( irlpt_clients, (FREE_FUNC) irlpt_client_close);
214 #ifdef CONFIG_PROC_FS
215 proc_unregister( &proc_irda, proc_irlpt_client.low_ino);
216 #endif
218 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
220 #endif /* MODULE */
224 * Function irlpt_open (void)
226 * This is the entry-point which starts all the fun! Currently this
229 static struct irlpt_cb *irlpt_client_open( __u32 daddr)
231 struct irlpt_cb *self;
233 DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
235 self = kmalloc(sizeof(struct irlpt_cb), GFP_ATOMIC);
236 if (self == NULL)
237 return NULL;
239 memset(self, 0, sizeof(struct irlpt_cb));
241 ASSERT( self != NULL, return NULL;);
243 sprintf(self->ifname, "irlpt%d", hashbin_get_size(irlpt_clients));
244 self->ir_dev.minor = MISC_DYNAMIC_MINOR;
245 self->ir_dev.name = self->ifname;
246 self->ir_dev.fops = &client_fops;
248 misc_register(&self->ir_dev);
250 self->magic = IRLPT_MAGIC;
251 self->in_use = TRUE;
252 self->servicetype = IRLPT_THREE_WIRE_RAW;
253 self->porttype = IRLPT_SERIAL;
255 skb_queue_head_init(&self->rx_queue);
257 irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
259 hashbin_insert( irlpt_clients, (QUEUE *) self, daddr, NULL);
261 /* MOD_INC_USE_COUNT; */
263 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
265 return self;
269 * Function irlpt_client_close (self)
271 * This function closes and marks the IrLPT instance as not in use.
273 static void irlpt_client_close( struct irlpt_cb *self)
275 struct sk_buff *skb;
277 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
279 ASSERT( self != NULL, return;);
280 ASSERT( self->magic == IRLPT_MAGIC, return;);
282 while (( skb = skb_dequeue(&self->rx_queue)) != NULL) {
283 DEBUG(3, "irlpt_client_close: freeing SKB\n");
284 dev_kfree_skb( skb);
287 misc_deregister(&self->ir_dev);
289 self->magic = ~IRLPT_MAGIC;
291 kfree( self);
293 /* MOD_DEC_USE_COUNT; */
295 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
299 * Function irlpt_discovery_indication (daddr)
301 * Remote device discovered, try query the remote IAS to see which
302 * device it is, and which services it has.
305 static void irlpt_client_discovery_indication( DISCOVERY *discovery)
307 struct irlpt_info info;
308 struct irlpt_cb *self;
309 __u32 daddr;
311 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
313 ASSERT( irlpt_clients != NULL, return;);
314 ASSERT( discovery != NULL, return;);
316 daddr = discovery->daddr;
319 * Check if an instance is already dealing with this device
320 * (daddr)
322 self = (struct irlpt_cb *) hashbin_find( irlpt_clients, daddr, NULL);
323 if ( self != NULL) {
324 ASSERT( self->magic == IRLPT_MAGIC, return;);
325 if ( self->state == IRLPT_CLIENT_IDLE) {
326 irlpt_client_do_event( self,
327 IRLPT_DISCOVERY_INDICATION,
328 NULL, &info);
330 return;
335 * We have no instance for daddr, so time to start a new instance.
336 * First we must find a free entry in master array
338 if (( self = irlpt_client_open( daddr)) == NULL) {
339 DEBUG(irlpt_client_debug, __FUNCTION__
340 ":irlpt_client_open failed!\n");
343 ASSERT(self != NULL, return;);
344 ASSERT(self->magic == IRLPT_MAGIC, return;);
346 self->daddr = info.daddr = daddr;
348 if (self->state == IRLPT_CLIENT_IDLE) {
349 irlpt_client_do_event( self, IRLPT_DISCOVERY_INDICATION,
350 NULL, &info);
353 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
357 * Function irlpt_disconnect_indication (handle)
360 static void irlpt_client_disconnect_indication( void *instance, void *sap,
361 LM_REASON reason,
362 struct sk_buff *skb)
364 struct irlpt_info info;
365 struct irlpt_cb *self;
367 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
369 self = ( struct irlpt_cb *) instance;
371 ASSERT( self != NULL, return;);
372 ASSERT( self->magic == IRLPT_MAGIC, return;);
374 info.daddr = self->daddr;
376 DEBUG( irlpt_client_debug, __FUNCTION__
377 ": reason=%d (%s), peersap=%d\n",
378 reason, irlpt_reasons[reason], self->dlsap_sel);
380 self->connected = IRLPT_DISCONNECTED;
381 self->eof = reason;
383 wake_up_interruptible( &self->write_wait);
385 irlpt_client_do_event( self, LMP_DISCONNECT, NULL, NULL);
387 if (skb) {
388 dev_kfree_skb( skb);
391 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
395 * Function irlpt_connect_confirm (handle, qos, skb)
397 * LSAP connection confirmed!
399 static void irlpt_client_connect_confirm( void *instance, void *sap,
400 struct qos_info *qos,
401 int max_sdu_size,
402 struct sk_buff *skb)
404 struct irlpt_info info;
405 struct irlpt_cb *self;
407 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
409 self = ( struct irlpt_cb *) instance;
411 ASSERT( self != NULL, return;);
412 ASSERT( self->magic == IRLPT_MAGIC, return;);
414 info.daddr = self->daddr;
417 * Check if we have got some QoS parameters back! This should be the
418 * negotiated QoS for the link.
420 if ( qos) {
421 DEBUG( irlpt_client_debug, __FUNCTION__ ": Frame Size: %d\n",
422 qos->data_size.value);
425 self->irlap_data_size = (qos->data_size.value - IRLPT_MAX_HEADER);
426 self->connected = TRUE;
428 irlpt_client_do_event( self, LMP_CONNECT, NULL, NULL);
430 if (skb) {
431 dev_kfree_skb( skb);
434 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
438 * Function client_data_indication (handle, skb)
440 * This function gets the data that is received on the data channel
443 static void irlpt_client_data_indication( void *instance, void *sap,
444 struct sk_buff *skb)
446 struct irlpt_cb *self;
448 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
450 ASSERT( skb != NULL, return;);
451 DEBUG( irlpt_client_debug, __FUNCTION__ ": len=%d\n", (int) skb->len);
453 self = ( struct irlpt_cb *) instance;
455 ASSERT( self != NULL, return;);
456 ASSERT( self->magic == IRLPT_MAGIC, return;);
457 #if 1
459 int i;
461 for(i=0;i<skb->len;i++)
462 if (skb->data[i] > 31 && skb->data[i] < 128) {
463 printk("%c", skb->data[i]);
464 } else {
465 if (skb->data[i] == 0x0d) {
466 printk("\n");
467 } else {
468 printk(".");
472 printk("\n");
474 #endif
476 skb_queue_tail(&self->rx_queue, skb);
477 wake_up_interruptible(&self->read_wait);
479 /* if (skb) { */
480 /* dev_kfree_skb( skb); */
481 /* } */
483 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
487 * Function irlpt_get_value_confirm (obj_id, type, value_int, value_char, priv)
489 * Fixed to match changes in iriap.h, DB.
493 void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value,
494 void *priv)
496 struct irlpt_info info;
497 struct irlpt_cb *self;
499 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
501 ASSERT( priv != NULL, return;);
503 self = (struct irlpt_cb *) priv;
505 ASSERT( self != NULL, return;);
506 ASSERT( self->magic == IRLPT_MAGIC, return;);
508 /* can't stop here.. if we get a bad obj, must tell the state
509 machine that!
510 ASSERT( type == IAS_INTEGER, return;);
513 if ( value->type == IAS_INTEGER && value->t.integer != -1) {
514 info.dlsap_sel = value->t.integer;
515 self->dlsap_sel = value->t.integer;
517 DEBUG( irlpt_client_debug, __FUNCTION__
518 ": obj_id = %d, value = %d\n",
519 obj_id, value->t.integer);
521 irlpt_client_do_event( self, IAS_PROVIDER_AVAIL,
522 NULL, &info);
523 } else
524 irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL,
525 NULL, &info);
527 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
530 void irlpt_client_connect_request( struct irlpt_cb *self)
532 struct notify_t lpt_notify;
534 DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
536 ASSERT( self != NULL, return;);
537 ASSERT( self->magic == IRLPT_MAGIC, return;);
539 lpt_notify.connect_confirm = irlpt_client_connect_confirm;
540 lpt_notify.disconnect_indication = irlpt_client_disconnect_indication;
541 lpt_notify.data_indication = irlpt_client_data_indication;
542 lpt_notify.instance = self;
544 self->lsap = irlmp_open_lsap( LSAP_ANY, &lpt_notify);
545 DEBUG( irlpt_client_debug, __FUNCTION__ ": Dest LSAP sel= %d\n",
546 self->dlsap_sel);
548 if (self->servicetype == IRLPT_THREE_WIRE_RAW) {
549 DEBUG( irlpt_client_debug, __FUNCTION__
550 ": issue THREE_WIRE_RAW connect\n");
551 irlmp_connect_request( self->lsap, self->dlsap_sel,
552 self->daddr, NULL, NULL);
555 DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
559 #ifdef MODULE
561 MODULE_AUTHOR("Thomas Davis <ratbert@radiks.net>");
562 MODULE_DESCRIPTION("The Linux IrDA/IrLPT protocol");
565 * Function init_module (void)
567 * Initialize the IrLPT client module, this function is called by the
568 * modprobe(1) program.
570 int init_module(void)
573 DEBUG( irlpt_client_debug, "--> irlpt client: init_module\n");
575 irlpt_client_init();
577 DEBUG( irlpt_client_debug, "irlpt client: init_module -->\n");
579 return 0;
583 * Function cleanup_module (void)
585 * Remove the IrLPT server module, this function is called by the rmmod(1)
586 * program
588 void cleanup_module(void)
590 DEBUG( irlpt_client_debug, "--> irlpt client: cleanup_module\n");
591 /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
593 /* Free some memory */
594 irlpt_client_cleanup();
596 DEBUG( irlpt_client_debug, "irlpt client: cleanup_module -->\n");
599 #endif /* MODULE */