patch-2.2.0-pre9 linux/net/irda/irlpt/irlpt_common.c
Next file: linux/net/irda/irlpt/irlpt_srvr.c
Previous file: linux/net/irda/irlpt/irlpt_cli_fsm.c
Back to the patch index
Back to the overall index
- Lines: 513
- Date:
Wed Jan 20 11:05:33 1999
- Orig file:
v2.2.0-pre8/linux/net/irda/irlpt/irlpt_common.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.2.0-pre8/linux/net/irda/irlpt/irlpt_common.c linux/net/irda/irlpt/irlpt_common.c
@@ -0,0 +1,512 @@
+/*********************************************************************
+ *
+ * Filename: irlpt_common.c
+ * Version:
+ * Description:
+ * Status: Experimental.
+ * Author: Thomas Davis, <ratbert@radiks.net>
+ * Created at: Sat Feb 21 18:54:38 1998
+ * Modified at: Sun Mar 8 23:44:19 1998
+ * Modified by: Dag Brattli <dagb@cs.uit.no>
+ * Sources: irlpt.c
+ *
+ * Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
+ * Copyright (c) 1998, Dag Brattli, <dagb@cs.uit.no>
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * I, Thomas Davis, provide no warranty for any of this software.
+ * This material is provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/segment.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlap.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irttp.h>
+#include <net/irda/timer.h>
+
+#include <net/irda/irlpt_common.h>
+/* #include "irlpt_client.h" */
+/* #include "irlpt_server.h" */
+
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+
+char *irlpt_service_type[] = {
+ "IRLPT_UNKNOWN",
+ "IRLPT_THREE_WIRE_RAW",
+ "IRLPT_THREE_WIRE",
+ "IRLPT_NINE_WIRE",
+ "IRLPT_CENTRONICS",
+ "IRLPT_SERVER_MODE",
+};
+
+char *irlpt_port_type[] = {
+ "IRLPT_UNKNOWN",
+ "IRLPT_SERIAL",
+ "IRLPT_PARALLEL",
+};
+
+char *irlpt_connected[] = {
+ "IRLPT_DISCONNECTED",
+ "IRLPT_WAITING",
+ "IRLPT_CONNECTED",
+ "IRLPT_FLUSHED",
+};
+
+char *irlpt_reasons[] = {
+ "SERVICE_CLOSE", /* Service has closed the connection */
+ "DISC_INDICATION", /* Received a disconnect request from peer entity*/
+ "NO_RESPONSE", /* To many retransmits without response */
+ "DEADLOCK_DETECTED", /* To many retransmits _with_ response */
+ "FOUND_NONE", /* No devices were discovered */
+ "MEDIA_BUSY",
+
+};
+
+char *irlpt_client_fsm_state[] = {
+ "IRLPT_CLIENT_IDLE",
+ "IRLPT_CLIENT_QUERY",
+ "IRLPT_CLIENT_READY",
+ "IRLPT_CLIENT_WAITI",
+ "IRLPT_CLIENT_WAITR",
+ "IRLPT_CLIENT_CONN"
+};
+
+char *irlpt_server_fsm_state[] = {
+ "IRLPT_SERVER_IDLE",
+ "IRLPT_SERVER_CONN"
+};
+
+char *irlpt_fsm_event[] = {
+ "QUERY_REMOTE_IAS",
+ "IAS_PROVIDER_AVAIL",
+ "IAS_PROVIDER_NOT_AVAIL",
+ "LAP_DISCONNECT",
+ "LMP_CONNECT",
+ "LMP_DISCONNECT",
+ "LMP_CONNECT_INDICATION",
+ "LMP_DISCONNECT_INDICATION",
+ "IRLPT_DISCOVERY_INDICATION",
+ "IRLPT_CONNECT_REQUEST",
+ "IRLPT_DISCONNECT_REQUEST",
+ "CLIENT_DATA_INDICATION",
+};
+
+hashbin_t *irlpt_clients = NULL;
+struct irlpt_cb *irlpt_server = NULL;
+int irlpt_common_debug = 4; /* want to change this? please don't!
+ use irlpt_common_debug=3 on the command line! */
+
+static struct wait_queue *irlpt_wait;
+
+#if 0
+static char *rcsid = "$Id: irlpt_common.c,v 1.6 1998/11/10 22:50:58 dagb Exp $";
+#endif
+
+struct irlpt_cb *irlpt_find_handle(unsigned int minor)
+{
+ struct irlpt_cb *self;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ /* Check for server */
+ if (irlpt_server != NULL && irlpt_server->ir_dev.minor == minor) {
+ DEBUG(irlpt_common_debug, __FUNCTION__
+ ": irlpt_server file handle!\n");
+ return irlpt_server;
+ }
+
+ /* Check the clients */
+ self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
+ while ( self) {
+ ASSERT( self->magic == IRLPT_MAGIC, return NULL;);
+
+ if ( minor == self->ir_dev.minor)
+ return self;
+
+ self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
+ }
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+
+ return NULL;
+}
+
+ssize_t irlpt_read( struct file *file, char *buffer, size_t count, loff_t
+ *noidea)
+{
+ int len=0;
+ char *ptr = buffer;
+ struct irlpt_cb *self;
+ struct sk_buff *skb = NULL;
+ struct wait_queue wait = { current, NULL };
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
+
+ ASSERT( self != NULL, return 0;);
+ ASSERT( self->magic == IRLPT_MAGIC, return 0;);
+
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": count=%d, skb_len=%d, connected=%d (%s) eof=%d\n",
+ count, skb_queue_len(&self->rx_queue), self->connected,
+ irlpt_connected[self->connected], self->eof);
+
+ if (self->eof && !skb_queue_len(&self->rx_queue)) {
+ switch (self->eof) {
+ case LM_USER_REQUEST:
+ self->eof = FALSE;
+ DEBUG(3, "irlpt_read: returning 0\n");
+ return 0;
+ case LM_LAP_DISCONNECT:
+ self->eof = FALSE;
+ return -EIO;
+ case LM_LAP_RESET:
+ self->eof = FALSE;
+ return -ECONNRESET;
+ default:
+ self->eof = FALSE;
+ return -EIO;
+ }
+ }
+
+ while (len <= count) {
+ skb = skb_dequeue(&self->rx_queue);
+
+ if (skb != NULL) {
+ DEBUG(irlpt_common_debug, __FUNCTION__
+ ": len=%d, skb->len=%d, count=%d\n",
+ len, (int) skb->len, count);
+
+ if ((skb->len + len) < count) {
+ copy_to_user(ptr, skb->data, skb->len);
+ len += skb->len;
+ ptr += skb->len;
+
+ dev_kfree_skb( skb);
+ } else {
+ skb_queue_head(&self->rx_queue, skb);
+ break;
+ }
+ } else {
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": skb=NULL, len=%d, count=%d, eof=%d\n",
+ len, count, self->eof);
+
+ if (!signal_pending(current) && !self->eof) {
+ add_wait_queue(&irlpt_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&irlpt_wait, &wait);
+ } else
+ break;
+ }
+ }
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ ": len=%d\n", len);
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+ return len;
+}
+
+ssize_t irlpt_write(struct file *file, const char *buffer,
+ size_t count, loff_t *noidea)
+{
+ struct irlpt_cb *self;
+ struct sk_buff *skb;
+ struct wait_queue wait = { current, NULL };
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
+
+ ASSERT( self != NULL, return 0;);
+ ASSERT( self->magic == IRLPT_MAGIC, return 0;);
+
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": count = %d\n", count);
+
+ if (self->state != IRLPT_CLIENT_CONN) {
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": state != IRLPT_CONN (possible link problems?)\n");
+ return -ENOLINK;
+ }
+
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": pkt_count = %d\n", self->pkt_count);
+ if (self->pkt_count > 8) {
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": too many outstanding buffers, going to sleep\n");
+ add_wait_queue(&self->write_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&self->write_wait, &wait);
+ }
+
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ":count = %d, irlap_data_size = %d, IRLPT_MAX_HEADER = %d\n",
+ count, self->irlap_data_size, IRLPT_MAX_HEADER);
+
+ if (count > (self->irlap_data_size - IRLPT_MAX_HEADER)) {
+ count = (self->irlap_data_size - IRLPT_MAX_HEADER);
+ DEBUG(irlpt_common_debug, __FUNCTION__
+ ": setting count to %d\n", count);
+ }
+
+ DEBUG( irlpt_common_debug, __FUNCTION__ ": count = %d\n", count);
+
+ skb = dev_alloc_skb(count + IRLPT_MAX_HEADER);
+ if ( skb == NULL) {
+ printk( KERN_INFO __FUNCTION__ ": couldn't allocate skbuff!\n");
+ return 0;
+ }
+
+ /*
+ * we use the unused stamp field to hold the device minor
+ * number, so we can look it up when the skb is destroyed.
+ */
+ *((__u32 *) &skb->stamp) = MINOR( file->f_dentry->d_inode->i_rdev);
+
+ skb_reserve( skb, IRLPT_MAX_HEADER);
+ skb_put( skb, count);
+
+ skb->destructor = irlpt_flow_control;
+ self->pkt_count++;
+
+ copy_from_user( skb->data, buffer, count);
+
+ irlmp_data_request(self->lsap, skb);
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+
+ return(count);
+}
+
+loff_t irlpt_seek( struct file *file, loff_t offset, int count)
+{
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+ return -ESPIPE;
+}
+
+#if 0
+
+/*
+ * Function irlpt_select (inode, filp, mode, table)
+ *
+ * Implementation for the select() call
+ *
+ */
+int irlpt_select( struct inode *inode, struct file *filp, int mode,
+ select_table *table)
+{
+ struct irlpt_cb *self;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle(MINOR( inode->i_rdev));
+
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRLPT_MAGIC, return -1;);
+
+ switch (mode) {
+ case SEL_IN:
+ if ( skb_queue_len( &self->rx_queue))
+ return 1; /* Readable */
+ select_wait( &self->read_wait, table);
+ break;
+ case SEL_OUT:
+ if ( self->connected)
+ return 1;
+ select_wait( &self->write_wait, table);
+ break;
+ case SEL_EX:
+ if ( self->connected)
+ return 1;
+ select_wait( &self->ex_wait, table);
+ break;
+ default:
+ break;
+ }
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+
+ return 0;
+}
+
+#else
+
+/*
+ * Function irobex_poll (file, wait)
+ *
+ *
+ *
+ */
+static u_int irlpt_poll(struct file *file, poll_table *wait)
+{
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ /* check out /usr/src/pcmcia/modules/ds.c for an example */
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+ return 0;
+}
+
+#endif
+
+/*
+ * Function open_irlpt (inode, file)
+ *
+ *
+ *
+ */
+int irlpt_open(struct inode *inode, struct file *file)
+{
+ struct irlpt_cb *self;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
+
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRLPT_MAGIC, return -1;);
+
+#if 0
+ if (self->state == IRLPT_IDLE) {
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": state == IRLPT_IDLE! (no device found yet)\n");
+ return -ENODEV;
+ }
+
+ if (self->state == IRLPT_QUERY ||
+ self->state == IRLPT_READY ||
+ self->state == IRLPT_WAITI) {
+ DEBUG( irlpt_common_debug, __FUNCTION__ ": state == IRLPT_QUERY, "
+ "IRLPT_READY or IRLPT_WAITI (link problems)!\n");
+ return -EBUSY;
+ }
+#endif
+
+ if (self->count++) {
+ DEBUG( irlpt_common_debug, __FUNCTION__
+ ": count not zero; actual = %d\n", self->count);
+ self->count--;
+ return -EBUSY;
+ }
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+
+ return 0;
+}
+
+/*
+ * Function close_irlpt (inode, file)
+ *
+ *
+ *
+ */
+int irlpt_close(struct inode *inode, struct file *file)
+{
+ struct irlpt_cb *self;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ ": have handle!\n");
+
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRLPT_MAGIC, return -1;);
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ ": self->count=%d\n", self->count);
+ if (self->count > 0)
+ self->count--;
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+
+ return 0;
+}
+
+void irlpt_dump_buffer( struct sk_buff *skb)
+{
+ int i;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ for(i=0;i<skb->len;i++)
+ if (skb->data[i] > 31 && skb->data[i] < 128) {
+ printk("%c", skb->data[i]);
+ } else {
+ if (skb->data[i] == 0x0d) {
+ printk("\n");
+ } else {
+ printk(".");
+ }
+ }
+
+ printk("\n");
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+}
+
+void irlpt_flow_control(struct sk_buff *skb)
+{
+ struct irlpt_cb *self;
+
+ DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
+
+ self = irlpt_find_handle( *((__u32 *) &skb->stamp));
+
+ self->pkt_count--;
+
+ ASSERT(self->pkt_count >= 0, return;);
+
+ DEBUG(irlpt_common_debug, __FUNCTION__
+ ": packet destroyed, count = %d\n", self->pkt_count);
+
+ wake_up_interruptible( &self->write_wait);
+
+ DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
+}
+
+#ifdef MODULE
+
+/*
+ * Function init_module (void)
+ *
+ * Initialize the module, this function is called by the
+ * modprobe(1) program.
+ */
+int init_module(void)
+{
+ return 0;
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ * Remove the module, this function is called by the rmmod(1)
+ * program
+ */
+void cleanup_module(void)
+{
+
+}
+
+#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov