1 /*********************************************************************
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>
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
,
56 static void irlpt_client_disconnect_indication( void *instance
, void *sap
,
58 struct sk_buff
*userdata
);
61 static char *rcsid
= "$Id: irlpt_client.c,v 1.10 1998/11/10 22:50:57 dagb Exp $";
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 */
73 irlpt_open
, /* open */
75 irlpt_close
, /* release */
78 NULL
, /* check_media_change */
79 NULL
, /* revalidate */
83 int irlpt_client_debug
= 4;
85 extern char *irlptstate
[];
90 * Function client_proc_read (buf, start, offset, len, unused)
93 static int irlpt_client_proc_read( char *buf
, char **start
, off_t offset
,
96 struct irlpt_cb
*self
;
99 len
= sprintf(buf
, "%s\n\n", version
);
101 self
= (struct irlpt_cb
*) hashbin_get_first( irlpt_clients
);
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
) {
113 case IRLPT_THREE_WIRE_RAW
:
116 case IRLPT_THREE_WIRE
:
119 case IRLPT_NINE_WIRE
:
122 case IRLPT_CENTRONICS
:
125 case IRLPT_SERVER_MODE
:
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
);
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");
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");
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
);
218 DEBUG( irlpt_client_debug
, __FUNCTION__
" -->\n");
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
);
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
;
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");
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
)
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");
287 misc_deregister(&self
->ir_dev
);
289 self
->magic
= ~IRLPT_MAGIC
;
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
;
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
322 self
= (struct irlpt_cb
*) hashbin_find( irlpt_clients
, daddr
, 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
,
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
,
353 DEBUG( irlpt_client_debug
, __FUNCTION__
" -->\n");
357 * Function irlpt_disconnect_indication (handle)
360 static void irlpt_client_disconnect_indication( void *instance
, void *sap
,
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
;
383 wake_up_interruptible( &self
->write_wait
);
385 irlpt_client_do_event( self
, LMP_DISCONNECT
, NULL
, NULL
);
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
,
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.
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
);
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
,
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;);
461 for(i
=0;i
<skb
->len
;i
++)
462 if (skb
->data
[i
] > 31 && skb
->data
[i
] < 128) {
463 printk("%c", skb
->data
[i
]);
465 if (skb
->data
[i
] == 0x0d) {
476 skb_queue_tail(&self
->rx_queue
, skb
);
477 wake_up_interruptible(&self
->read_wait
);
480 /* dev_kfree_skb( skb); */
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
,
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
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
,
524 irlpt_client_do_event( self
, IAS_PROVIDER_NOT_AVAIL
,
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",
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");
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");
577 DEBUG( irlpt_client_debug
, "irlpt client: init_module -->\n");
583 * Function cleanup_module (void)
585 * Remove the IrLPT server module, this function is called by the rmmod(1)
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");