2.2.0-final
[davej-history.git] / net / irda / irlpt / irlpt_common.c
blob342f1a13fa13289f5c511dd8eb407d61dfa12c9d
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/config.h>
28 #include <linux/module.h>
30 #include <asm/segment.h>
32 #include <net/irda/irda.h>
33 #include <net/irda/irlap.h>
34 #include <net/irda/irlmp.h>
35 #include <net/irda/iriap.h>
36 #include <net/irda/irttp.h>
37 #include <net/irda/timer.h>
39 #include <net/irda/irlpt_common.h>
40 /* #include "irlpt_client.h" */
41 /* #include "irlpt_server.h" */
43 #include <asm/uaccess.h>
44 #include <linux/miscdevice.h>
45 #include <linux/proc_fs.h>
46 #include <linux/fs.h>
48 char *irlpt_service_type[] = {
49 "IRLPT_UNKNOWN",
50 "IRLPT_THREE_WIRE_RAW",
51 "IRLPT_THREE_WIRE",
52 "IRLPT_NINE_WIRE",
53 "IRLPT_CENTRONICS",
54 "IRLPT_SERVER_MODE",
57 char *irlpt_port_type[] = {
58 "IRLPT_UNKNOWN",
59 "IRLPT_SERIAL",
60 "IRLPT_PARALLEL",
63 char *irlpt_connected[] = {
64 "IRLPT_DISCONNECTED",
65 "IRLPT_WAITING",
66 "IRLPT_CONNECTED",
67 "IRLPT_FLUSHED",
70 char *irlpt_reasons[] = {
71 "SERVICE_CLOSE", /* Service has closed the connection */
72 "DISC_INDICATION", /* Received a disconnect request from peer entity*/
73 "NO_RESPONSE", /* To many retransmits without response */
74 "DEADLOCK_DETECTED", /* To many retransmits _with_ response */
75 "FOUND_NONE", /* No devices were discovered */
76 "MEDIA_BUSY",
80 char *irlpt_client_fsm_state[] = {
81 "IRLPT_CLIENT_IDLE",
82 "IRLPT_CLIENT_QUERY",
83 "IRLPT_CLIENT_READY",
84 "IRLPT_CLIENT_WAITI",
85 "IRLPT_CLIENT_WAITR",
86 "IRLPT_CLIENT_CONN"
89 char *irlpt_server_fsm_state[] = {
90 "IRLPT_SERVER_IDLE",
91 "IRLPT_SERVER_CONN"
94 char *irlpt_fsm_event[] = {
95 "QUERY_REMOTE_IAS",
96 "IAS_PROVIDER_AVAIL",
97 "IAS_PROVIDER_NOT_AVAIL",
98 "LAP_DISCONNECT",
99 "LMP_CONNECT",
100 "LMP_DISCONNECT",
101 "LMP_CONNECT_INDICATION",
102 "LMP_DISCONNECT_INDICATION",
103 "IRLPT_DISCOVERY_INDICATION",
104 "IRLPT_CONNECT_REQUEST",
105 "IRLPT_DISCONNECT_REQUEST",
106 "CLIENT_DATA_INDICATION",
109 hashbin_t *irlpt_clients = NULL;
110 struct irlpt_cb *irlpt_server = NULL;
111 int irlpt_common_debug = 4; /* want to change this? please don't!
112 use irlpt_common_debug=3 on the command line! */
114 static struct wait_queue *irlpt_wait;
116 #if 0
117 static char *rcsid = "$Id: irlpt_common.c,v 1.6 1998/11/10 22:50:58 dagb Exp $";
118 #endif
120 struct irlpt_cb *irlpt_find_handle(unsigned int minor)
122 struct irlpt_cb *self;
124 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
126 /* Check for server */
127 if (irlpt_server != NULL && irlpt_server->ir_dev.minor == minor) {
128 DEBUG(irlpt_common_debug, __FUNCTION__
129 ": irlpt_server file handle!\n");
130 return irlpt_server;
133 /* Check the clients */
134 self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
135 while ( self) {
136 ASSERT( self->magic == IRLPT_MAGIC, return NULL;);
138 if ( minor == self->ir_dev.minor)
139 return self;
141 self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
144 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
146 return NULL;
149 ssize_t irlpt_read( struct file *file, char *buffer, size_t count, loff_t
150 *noidea)
152 int len=0;
153 char *ptr = buffer;
154 struct irlpt_cb *self;
155 struct sk_buff *skb = NULL;
156 struct wait_queue wait = { current, NULL };
158 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
160 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
162 ASSERT( self != NULL, return 0;);
163 ASSERT( self->magic == IRLPT_MAGIC, return 0;);
165 DEBUG( irlpt_common_debug, __FUNCTION__
166 ": count=%d, skb_len=%d, connected=%d (%s) eof=%d\n",
167 count, skb_queue_len(&self->rx_queue), self->connected,
168 irlpt_connected[self->connected], self->eof);
170 if (self->eof && !skb_queue_len(&self->rx_queue)) {
171 switch (self->eof) {
172 case LM_USER_REQUEST:
173 self->eof = FALSE;
174 DEBUG(3, "irlpt_read: returning 0\n");
175 return 0;
176 case LM_LAP_DISCONNECT:
177 self->eof = FALSE;
178 return -EIO;
179 case LM_LAP_RESET:
180 self->eof = FALSE;
181 return -ECONNRESET;
182 default:
183 self->eof = FALSE;
184 return -EIO;
188 while (len <= count) {
189 skb = skb_dequeue(&self->rx_queue);
191 if (skb != NULL) {
192 DEBUG(irlpt_common_debug, __FUNCTION__
193 ": len=%d, skb->len=%d, count=%d\n",
194 len, (int) skb->len, count);
196 if ((skb->len + len) < count) {
197 copy_to_user(ptr, skb->data, skb->len);
198 len += skb->len;
199 ptr += skb->len;
201 dev_kfree_skb( skb);
202 } else {
203 skb_queue_head(&self->rx_queue, skb);
204 break;
206 } else {
207 DEBUG( irlpt_common_debug, __FUNCTION__
208 ": skb=NULL, len=%d, count=%d, eof=%d\n",
209 len, count, self->eof);
211 if (!signal_pending(current) && !self->eof) {
212 add_wait_queue(&irlpt_wait, &wait);
213 current->state = TASK_INTERRUPTIBLE;
214 schedule();
215 current->state = TASK_RUNNING;
216 remove_wait_queue(&irlpt_wait, &wait);
217 } else
218 break;
222 DEBUG(irlpt_common_debug, __FUNCTION__ ": len=%d\n", len);
223 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
224 return len;
227 ssize_t irlpt_write(struct file *file, const char *buffer,
228 size_t count, loff_t *noidea)
230 struct irlpt_cb *self;
231 struct sk_buff *skb;
232 struct wait_queue wait = { current, NULL };
234 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
236 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
238 ASSERT( self != NULL, return 0;);
239 ASSERT( self->magic == IRLPT_MAGIC, return 0;);
241 DEBUG( irlpt_common_debug, __FUNCTION__
242 ": count = %d\n", count);
244 if (self->state != IRLPT_CLIENT_CONN) {
245 DEBUG( irlpt_common_debug, __FUNCTION__
246 ": state != IRLPT_CONN (possible link problems?)\n");
247 return -ENOLINK;
250 DEBUG( irlpt_common_debug, __FUNCTION__
251 ": pkt_count = %d\n", self->pkt_count);
252 if (self->pkt_count > 8) {
253 DEBUG( irlpt_common_debug, __FUNCTION__
254 ": too many outstanding buffers, going to sleep\n");
255 add_wait_queue(&self->write_wait, &wait);
256 current->state = TASK_INTERRUPTIBLE;
257 schedule();
258 current->state = TASK_RUNNING;
259 remove_wait_queue(&self->write_wait, &wait);
262 DEBUG( irlpt_common_debug, __FUNCTION__
263 ":count = %d, irlap_data_size = %d, IRLPT_MAX_HEADER = %d\n",
264 count, self->irlap_data_size, IRLPT_MAX_HEADER);
266 if (count > (self->irlap_data_size - IRLPT_MAX_HEADER)) {
267 count = (self->irlap_data_size - IRLPT_MAX_HEADER);
268 DEBUG(irlpt_common_debug, __FUNCTION__
269 ": setting count to %d\n", count);
272 DEBUG( irlpt_common_debug, __FUNCTION__ ": count = %d\n", count);
274 skb = dev_alloc_skb(count + IRLPT_MAX_HEADER);
275 if ( skb == NULL) {
276 printk( KERN_INFO __FUNCTION__ ": couldn't allocate skbuff!\n");
277 return 0;
281 * we use the unused stamp field to hold the device minor
282 * number, so we can look it up when the skb is destroyed.
284 *((__u32 *) &skb->stamp) = MINOR( file->f_dentry->d_inode->i_rdev);
286 skb_reserve( skb, IRLPT_MAX_HEADER);
287 skb_put( skb, count);
289 skb->destructor = irlpt_flow_control;
290 self->pkt_count++;
292 copy_from_user( skb->data, buffer, count);
294 irlmp_data_request(self->lsap, skb);
296 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
298 return(count);
301 loff_t irlpt_seek( struct file *file, loff_t offset, int count)
303 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
305 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
306 return -ESPIPE;
309 #if 0
312 * Function irlpt_select (inode, filp, mode, table)
314 * Implementation for the select() call
317 int irlpt_select( struct inode *inode, struct file *filp, int mode,
318 select_table *table)
320 struct irlpt_cb *self;
322 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
324 self = irlpt_find_handle(MINOR( inode->i_rdev));
326 ASSERT( self != NULL, return -1;);
327 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
329 switch (mode) {
330 case SEL_IN:
331 if ( skb_queue_len( &self->rx_queue))
332 return 1; /* Readable */
333 select_wait( &self->read_wait, table);
334 break;
335 case SEL_OUT:
336 if ( self->connected)
337 return 1;
338 select_wait( &self->write_wait, table);
339 break;
340 case SEL_EX:
341 if ( self->connected)
342 return 1;
343 select_wait( &self->ex_wait, table);
344 break;
345 default:
346 break;
349 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
351 return 0;
354 #else
357 * Function irobex_poll (file, wait)
362 static u_int irlpt_poll(struct file *file, poll_table *wait)
364 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
366 /* check out /usr/src/pcmcia/modules/ds.c for an example */
367 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
368 return 0;
371 #endif
374 * Function open_irlpt (inode, file)
379 int irlpt_open(struct inode *inode, struct file *file)
381 struct irlpt_cb *self;
383 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
385 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
387 ASSERT( self != NULL, return -1;);
388 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
390 #if 0
391 if (self->state == IRLPT_IDLE) {
392 DEBUG( irlpt_common_debug, __FUNCTION__
393 ": state == IRLPT_IDLE! (no device found yet)\n");
394 return -ENODEV;
397 if (self->state == IRLPT_QUERY ||
398 self->state == IRLPT_READY ||
399 self->state == IRLPT_WAITI) {
400 DEBUG( irlpt_common_debug, __FUNCTION__ ": state == IRLPT_QUERY, "
401 "IRLPT_READY or IRLPT_WAITI (link problems)!\n");
402 return -EBUSY;
404 #endif
406 if (self->count++) {
407 DEBUG( irlpt_common_debug, __FUNCTION__
408 ": count not zero; actual = %d\n", self->count);
409 self->count--;
410 return -EBUSY;
413 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
415 return 0;
419 * Function close_irlpt (inode, file)
424 int irlpt_close(struct inode *inode, struct file *file)
426 struct irlpt_cb *self;
428 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
430 self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
432 DEBUG(irlpt_common_debug, __FUNCTION__ ": have handle!\n");
434 ASSERT( self != NULL, return -1;);
435 ASSERT( self->magic == IRLPT_MAGIC, return -1;);
437 DEBUG(irlpt_common_debug, __FUNCTION__ ": self->count=%d\n", self->count);
438 if (self->count > 0)
439 self->count--;
441 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
443 return 0;
446 void irlpt_dump_buffer( struct sk_buff *skb)
448 int i;
450 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
452 for(i=0;i<skb->len;i++)
453 if (skb->data[i] > 31 && skb->data[i] < 128) {
454 printk("%c", skb->data[i]);
455 } else {
456 if (skb->data[i] == 0x0d) {
457 printk("\n");
458 } else {
459 printk(".");
463 printk("\n");
465 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
468 void irlpt_flow_control(struct sk_buff *skb)
470 struct irlpt_cb *self;
472 DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
474 self = irlpt_find_handle( *((__u32 *) &skb->stamp));
476 self->pkt_count--;
478 ASSERT(self->pkt_count >= 0, return;);
480 DEBUG(irlpt_common_debug, __FUNCTION__
481 ": packet destroyed, count = %d\n", self->pkt_count);
483 wake_up_interruptible( &self->write_wait);
485 DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
488 #ifdef MODULE
491 * Function init_module (void)
493 * Initialize the module, this function is called by the
494 * modprobe(1) program.
496 int init_module(void)
498 return 0;
502 * Function cleanup_module (void)
504 * Remove the module, this function is called by the rmmod(1)
505 * program
507 void cleanup_module(void)
512 #endif /* MODULE */