Linux 2.2.0
[davej-history.git] / net / irda / irlpt / irlpt_common.c
blob886eb30a02d109657b8a54d810b06ff7214dd31e
1 /*********************************************************************
3 * Filename: irlpt_common.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: irlpt.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 <linux/module.h>
29 #include <asm/segment.h>
31 #include <net/irda/irda.h>
32 #include <net/irda/irlap.h>
33 #include <net/irda/irlmp.h>
34 #include <net/irda/iriap.h>
35 #include <net/irda/irttp.h>
36 #include <net/irda/timer.h>
38 #include <net/irda/irlpt_common.h>
39 /* #include "irlpt_client.h" */
40 /* #include "irlpt_server.h" */
42 #include <asm/uaccess.h>
43 #include <linux/miscdevice.h>
44 #include <linux/proc_fs.h>
45 #include <linux/fs.h>
47 char *irlpt_service_type[] = {
48 "IRLPT_UNKNOWN",
49 "IRLPT_THREE_WIRE_RAW",
50 "IRLPT_THREE_WIRE",
51 "IRLPT_NINE_WIRE",
52 "IRLPT_CENTRONICS",
53 "IRLPT_SERVER_MODE",
56 char *irlpt_port_type[] = {
57 "IRLPT_UNKNOWN",
58 "IRLPT_SERIAL",
59 "IRLPT_PARALLEL",
62 char *irlpt_connected[] = {
63 "IRLPT_DISCONNECTED",
64 "IRLPT_WAITING",
65 "IRLPT_CONNECTED",
66 "IRLPT_FLUSHED",
69 char *irlpt_reasons[] = {
70 "SERVICE_CLOSE", /* Service has closed the connection */
71 "DISC_INDICATION", /* Received a disconnect request from peer entity*/
72 "NO_RESPONSE", /* To many retransmits without response */
73 "DEADLOCK_DETECTED", /* To many retransmits _with_ response */
74 "FOUND_NONE", /* No devices were discovered */
75 "MEDIA_BUSY",
79 char *irlpt_client_fsm_state[] = {
80 "IRLPT_CLIENT_IDLE",
81 "IRLPT_CLIENT_QUERY",
82 "IRLPT_CLIENT_READY",
83 "IRLPT_CLIENT_WAITI",
84 "IRLPT_CLIENT_WAITR",
85 "IRLPT_CLIENT_CONN"
88 char *irlpt_server_fsm_state[] = {
89 "IRLPT_SERVER_IDLE",
90 "IRLPT_SERVER_CONN"
93 char *irlpt_fsm_event[] = {
94 "QUERY_REMOTE_IAS",
95 "IAS_PROVIDER_AVAIL",
96 "IAS_PROVIDER_NOT_AVAIL",
97 "LAP_DISCONNECT",
98 "LMP_CONNECT",
99 "LMP_DISCONNECT",
100 "LMP_CONNECT_INDICATION",
101 "LMP_DISCONNECT_INDICATION",
102 "IRLPT_DISCOVERY_INDICATION",
103 "IRLPT_CONNECT_REQUEST",
104 "IRLPT_DISCONNECT_REQUEST",
105 "CLIENT_DATA_INDICATION",
108 hashbin_t *irlpt_clients = NULL;
109 struct irlpt_cb *irlpt_server = NULL;
110 int irlpt_common_debug = 4; /* want to change this? please don't!
111 use irlpt_common_debug=3 on the command line! */
113 static struct wait_queue *irlpt_wait;
115 #if 0
116 static char *rcsid = "$Id: irlpt_common.c,v 1.6 1998/11/10 22:50:58 dagb Exp $";
117 #endif
119 struct irlpt_cb *irlpt_find_handle(unsigned int minor)
121 struct irlpt_cb *self;
123 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
125 /* Check for server */
126 if (irlpt_server != NULL && irlpt_server->ir_dev.minor == minor) {
127 DEBUG(irlpt_common_debug, __FUNCTION__
128 ": irlpt_server file handle!\n");
129 return irlpt_server;
132 /* Check the clients */
133 self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
134 while ( self) {
135 ASSERT( self->magic == IRLPT_MAGIC, return NULL;);
137 if ( minor == self->ir_dev.minor)
138 return self;
140 self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
143 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
145 return NULL;
148 ssize_t irlpt_read( struct file *file, char *buffer, size_t count, loff_t
149 *noidea)
151 int len=0;
152 char *ptr = buffer;
153 struct irlpt_cb *self;
154 struct sk_buff *skb = NULL;
155 struct wait_queue wait = { current, NULL };
157 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
159 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
161 ASSERT( self != NULL, return 0;);
162 ASSERT( self->magic == IRLPT_MAGIC, return 0;);
164 DEBUG( irlpt_common_debug, __FUNCTION__
165 ": count=%d, skb_len=%d, connected=%d (%s) eof=%d\n",
166 count, skb_queue_len(&self->rx_queue), self->connected,
167 irlpt_connected[self->connected], self->eof);
169 if (self->eof && !skb_queue_len(&self->rx_queue)) {
170 switch (self->eof) {
171 case LM_USER_REQUEST:
172 self->eof = FALSE;
173 DEBUG(3, "irlpt_read: returning 0\n");
174 return 0;
175 case LM_LAP_DISCONNECT:
176 self->eof = FALSE;
177 return -EIO;
178 case LM_LAP_RESET:
179 self->eof = FALSE;
180 return -ECONNRESET;
181 default:
182 self->eof = FALSE;
183 return -EIO;
187 while (len <= count) {
188 skb = skb_dequeue(&self->rx_queue);
190 if (skb != NULL) {
191 DEBUG(irlpt_common_debug, __FUNCTION__
192 ": len=%d, skb->len=%d, count=%d\n",
193 len, (int) skb->len, count);
195 if ((skb->len + len) < count) {
196 copy_to_user(ptr, skb->data, skb->len);
197 len += skb->len;
198 ptr += skb->len;
200 dev_kfree_skb( skb);
201 } else {
202 skb_queue_head(&self->rx_queue, skb);
203 break;
205 } else {
206 DEBUG( irlpt_common_debug, __FUNCTION__
207 ": skb=NULL, len=%d, count=%d, eof=%d\n",
208 len, count, self->eof);
210 if (!signal_pending(current) && !self->eof) {
211 add_wait_queue(&irlpt_wait, &wait);
212 current->state = TASK_INTERRUPTIBLE;
213 schedule();
214 current->state = TASK_RUNNING;
215 remove_wait_queue(&irlpt_wait, &wait);
216 } else
217 break;
221 DEBUG(irlpt_common_debug, __FUNCTION__ ": len=%d\n", len);
222 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
223 return len;
226 ssize_t irlpt_write(struct file *file, const char *buffer,
227 size_t count, loff_t *noidea)
229 struct irlpt_cb *self;
230 struct sk_buff *skb;
231 struct wait_queue wait = { current, NULL };
233 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
235 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
237 ASSERT( self != NULL, return 0;);
238 ASSERT( self->magic == IRLPT_MAGIC, return 0;);
240 DEBUG( irlpt_common_debug, __FUNCTION__
241 ": count = %d\n", count);
243 if (self->state != IRLPT_CLIENT_CONN) {
244 DEBUG( irlpt_common_debug, __FUNCTION__
245 ": state != IRLPT_CONN (possible link problems?)\n");
246 return -ENOLINK;
249 DEBUG( irlpt_common_debug, __FUNCTION__
250 ": pkt_count = %d\n", self->pkt_count);
251 if (self->pkt_count > 8) {
252 DEBUG( irlpt_common_debug, __FUNCTION__
253 ": too many outstanding buffers, going to sleep\n");
254 add_wait_queue(&self->write_wait, &wait);
255 current->state = TASK_INTERRUPTIBLE;
256 schedule();
257 current->state = TASK_RUNNING;
258 remove_wait_queue(&self->write_wait, &wait);
261 DEBUG( irlpt_common_debug, __FUNCTION__
262 ":count = %d, irlap_data_size = %d, IRLPT_MAX_HEADER = %d\n",
263 count, self->irlap_data_size, IRLPT_MAX_HEADER);
265 if (count > (self->irlap_data_size - IRLPT_MAX_HEADER)) {
266 count = (self->irlap_data_size - IRLPT_MAX_HEADER);
267 DEBUG(irlpt_common_debug, __FUNCTION__
268 ": setting count to %d\n", count);
271 DEBUG( irlpt_common_debug, __FUNCTION__ ": count = %d\n", count);
273 skb = dev_alloc_skb(count + IRLPT_MAX_HEADER);
274 if ( skb == NULL) {
275 printk( KERN_INFO __FUNCTION__ ": couldn't allocate skbuff!\n");
276 return 0;
280 * we use the unused stamp field to hold the device minor
281 * number, so we can look it up when the skb is destroyed.
283 *((__u32 *) &skb->stamp) = MINOR( file->f_dentry->d_inode->i_rdev);
285 skb_reserve( skb, IRLPT_MAX_HEADER);
286 skb_put( skb, count);
288 skb->destructor = irlpt_flow_control;
289 self->pkt_count++;
291 copy_from_user( skb->data, buffer, count);
293 irlmp_data_request(self->lsap, skb);
295 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
297 return(count);
300 loff_t irlpt_seek( struct file *file, loff_t offset, int count)
302 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
304 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
305 return -ESPIPE;
308 #if 0
311 * Function irlpt_select (inode, filp, mode, table)
313 * Implementation for the select() call
316 int irlpt_select( struct inode *inode, struct file *filp, int mode,
317 select_table *table)
319 struct irlpt_cb *self;
321 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
323 self = irlpt_find_handle(MINOR( inode->i_rdev));
325 ASSERT( self != NULL, return -1;);
326 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
328 switch (mode) {
329 case SEL_IN:
330 if ( skb_queue_len( &self->rx_queue))
331 return 1; /* Readable */
332 select_wait( &self->read_wait, table);
333 break;
334 case SEL_OUT:
335 if ( self->connected)
336 return 1;
337 select_wait( &self->write_wait, table);
338 break;
339 case SEL_EX:
340 if ( self->connected)
341 return 1;
342 select_wait( &self->ex_wait, table);
343 break;
344 default:
345 break;
348 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
350 return 0;
353 #else
356 * Function irobex_poll (file, wait)
361 static u_int irlpt_poll(struct file *file, poll_table *wait)
363 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
365 /* check out /usr/src/pcmcia/modules/ds.c for an example */
366 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
367 return 0;
370 #endif
373 * Function open_irlpt (inode, file)
378 int irlpt_open(struct inode *inode, struct file *file)
380 struct irlpt_cb *self;
382 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
384 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
386 ASSERT( self != NULL, return -1;);
387 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
389 #if 0
390 if (self->state == IRLPT_IDLE) {
391 DEBUG( irlpt_common_debug, __FUNCTION__
392 ": state == IRLPT_IDLE! (no device found yet)\n");
393 return -ENODEV;
396 if (self->state == IRLPT_QUERY ||
397 self->state == IRLPT_READY ||
398 self->state == IRLPT_WAITI) {
399 DEBUG( irlpt_common_debug, __FUNCTION__ ": state == IRLPT_QUERY, "
400 "IRLPT_READY or IRLPT_WAITI (link problems)!\n");
401 return -EBUSY;
403 #endif
405 if (self->count++) {
406 DEBUG( irlpt_common_debug, __FUNCTION__
407 ": count not zero; actual = %d\n", self->count);
408 self->count--;
409 return -EBUSY;
412 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
414 return 0;
418 * Function close_irlpt (inode, file)
423 int irlpt_close(struct inode *inode, struct file *file)
425 struct irlpt_cb *self;
427 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
429 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
431 DEBUG(irlpt_common_debug, __FUNCTION__ ": have handle!\n");
433 ASSERT( self != NULL, return -1;);
434 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
436 DEBUG(irlpt_common_debug, __FUNCTION__ ": self->count=%d\n", self->count);
437 if (self->count > 0)
438 self->count--;
440 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
442 return 0;
445 void irlpt_dump_buffer( struct sk_buff *skb)
447 int i;
449 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
451 for(i=0;i<skb->len;i++)
452 if (skb->data[i] > 31 && skb->data[i] < 128) {
453 printk("%c", skb->data[i]);
454 } else {
455 if (skb->data[i] == 0x0d) {
456 printk("\n");
457 } else {
458 printk(".");
462 printk("\n");
464 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
467 void irlpt_flow_control(struct sk_buff *skb)
469 struct irlpt_cb *self;
471 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
473 self = irlpt_find_handle( *((__u32 *) &skb->stamp));
475 self->pkt_count--;
477 ASSERT(self->pkt_count >= 0, return;);
479 DEBUG(irlpt_common_debug, __FUNCTION__
480 ": packet destroyed, count = %d\n", self->pkt_count);
482 wake_up_interruptible( &self->write_wait);
484 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
487 #ifdef MODULE
490 * Function init_module (void)
492 * Initialize the module, this function is called by the
493 * modprobe(1) program.
495 int init_module(void)
497 return 0;
501 * Function cleanup_module (void)
503 * Remove the module, this function is called by the rmmod(1)
504 * program
506 void cleanup_module(void)
511 #endif /* MODULE */