patch-2.1.132 linux/net/irda/irda_device.c
Next file: linux/net/irda/iriap.c
Previous file: linux/net/irda/ircomm/irvtd_driver.c
Back to the patch index
Back to the overall index
- Lines: 579
- Date:
Thu Dec 17 09:01:03 1998
- Orig file:
v2.1.131/linux/net/irda/irda_device.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.131/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
@@ -0,0 +1,578 @@
+/*********************************************************************
+ *
+ * Filename: irda_device.c
+ * Version:
+ * Description:
+ * Status: Experimental.
+ * Author: Dag Brattli <dagb@cs.uit.no>
+ * Created at: Wed Sep 2 20:22:08 1998
+ * Modified at: Mon Dec 14 19:18:51 1998
+ * Modified by: Dag Brattli <dagb@cs.uit.no>
+ *
+ * Copyright (c) 1998 Dag Brattli, 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.
+ *
+ * Neither Dag Brattli nor University of Tromsų admit liability nor
+ * provide warranty for any of this software. This material is
+ * provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+
+#include <net/pkt_sched.h>
+#include <asm/dma.h>
+
+#include <net/irda/irda_device.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/timer.h>
+#include <net/irda/wrapper.h>
+
+extern int irtty_init(void);
+extern int pc87108_init(void);
+extern int w83977af_init(void);
+extern int esi_init(void);
+extern int tekram_init(void);
+extern int actisys_init(void);
+
+hashbin_t *irda_device = NULL;
+
+void irda_device_start_todo_timer( struct irda_device *self, int timeout);
+
+/* Netdevice functions */
+static int irda_device_net_rebuild_header(struct sk_buff *skb);
+static int irda_device_net_hard_header(struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len);
+static int irda_device_net_set_config( struct device *dev, struct ifmap *map);
+static int irda_device_net_change_mtu( struct device *dev, int new_mtu);
+
+#ifdef CONFIG_PROC_FS
+int irda_device_proc_read( char *buf, char **start, off_t offset, int len,
+ int unused);
+
+#endif /* CONFIG_PROC_FS */
+
+__initfunc(int irda_device_init( void))
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ /* Allocate master array */
+ irda_device = hashbin_new( HB_LOCAL);
+ if ( irda_device == NULL) {
+ printk( KERN_WARNING "IrDA: Can't allocate irda_device hashbin!\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Call the init function of the device drivers that has not been
+ * compiled as a module
+ */
+#ifdef CONFIG_IRTTY_SIR
+ irtty_init();
+#endif
+#ifdef CONFIG_WINBOND_FIR
+ w83977af_init();
+#endif
+#ifdef CONFIG_NSC_FIR
+ pc87108_init();
+#endif
+#ifdef CONFIG_ESI_DONGLE
+ esi_init();
+#endif
+#ifdef CONFIG_TEKRAM_DONGLE
+ tekram_init();
+#endif
+#ifdef CONFIG_ACTISYS_DONGLE
+ actisys_init();
+#endif
+
+ return 0;
+}
+
+void irda_device_cleanup(void)
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( irda_device != NULL, return;);
+
+ hashbin_delete( irda_device, (FREE_FUNC) irda_device_close);
+}
+
+/*
+ * Function irda_device_open (self)
+ *
+ * Open a new IrDA port device
+ *
+ */
+int irda_device_open( struct irda_device *self, char *name, void *priv)
+{
+ int result;
+ int i=0;
+
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ /* Check that a minimum of allocation flags are specified */
+ ASSERT(( self->rx_buff.flags & (GFP_KERNEL|GFP_ATOMIC)) != 0,
+ return -1;);
+ ASSERT(( self->tx_buff.flags & (GFP_KERNEL|GFP_ATOMIC)) != 0,
+ return -1;);
+
+ ASSERT( self->tx_buff.truesize > 0, return -1;);
+ ASSERT( self->rx_buff.truesize > 0, return -1;);
+
+ self->rx_buff.data = ( __u8 *) kmalloc( self->rx_buff.truesize,
+ self->rx_buff.flags);
+ self->tx_buff.data = ( __u8 *) kmalloc( self->tx_buff.truesize,
+ self->tx_buff.flags);
+
+ if ( self->rx_buff.data == NULL || self->tx_buff.data == NULL) {
+ DEBUG( 0, "IrDA Self: no space for buffers!\n");
+ irda_device_close( self);
+ return -ENOMEM;
+ }
+
+ memset( self->rx_buff.data, 0, self->rx_buff.truesize);
+ memset( self->tx_buff.data, 0, self->tx_buff.truesize);
+
+ self->magic = IRDA_DEVICE_MAGIC;
+
+ self->rx_buff.in_frame = FALSE;
+ self->rx_buff.state = OUTSIDE_FRAME;
+
+ /* Initialize timers */
+ init_timer( &self->media_busy_timer);
+
+ /* Open new IrLAP layer instance */
+ self->irlap = irlap_open( self);
+
+ /* A pointer to the low level implementation */
+ self->priv = priv;
+ strncpy( self->name, name, 16);
+
+ /* Initialize IrDA net device */
+ do {
+ sprintf( self->name, "%s%d", "irda", i++);
+ } while ( dev_get( self->name) != NULL);
+
+ self->netdev.name = self->name;
+ self->netdev.priv = (void *) self;
+ self->netdev.next = NULL;
+
+ if (( result = register_netdev( &self->netdev)) != 0) {
+ DEBUG( 0, "IrDA Device, register_netdev() failed!\n");
+ return -1;
+ }
+
+ hashbin_insert( irda_device, (QUEUE *) self, (int) self, NULL);
+
+ /* Open network device */
+ dev_open( &self->netdev);
+
+ printk( "IrDA irda_device %s registered.\n", self->name);
+
+ irda_device_set_media_busy( self, FALSE);
+
+ return 0;
+}
+
+/*
+ * Function irda_device_close (self)
+ *
+ * Close this instance of the irda_device, just deallocate buffers
+ *
+ */
+void __irda_device_close( struct irda_device *self)
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+
+ dev_close( &self->netdev);
+
+ /* Remove netdevice */
+ unregister_netdev( &self->netdev);
+
+ /* Stop timers */
+ del_timer( &self->todo_timer);
+ del_timer( &self->media_busy_timer);
+
+ if ( self->tx_buff.data) {
+ kfree( self->tx_buff.data);
+ }
+
+ if ( self->rx_buff.data) {
+ kfree( self->rx_buff.data);
+ }
+
+ self->magic = 0;
+}
+
+/*
+ * Function irda_device_close (self)
+ *
+ *
+ *
+ */
+void irda_device_close( struct irda_device *self)
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+
+ /* Stop IrLAP */
+ irlap_close( self->irlap);
+ self->irlap = NULL;
+
+ hashbin_remove( irda_device, (int) self, NULL);
+
+ __irda_device_close( self);
+}
+
+/*
+ * Function irda_device_set_media_busy (self, status)
+ *
+ * Called when we have detected that another station is transmiting
+ * in contention mode.
+ */
+void irda_device_set_media_busy( struct irda_device *self, int status)
+{
+ DEBUG( 4, __FUNCTION__ "(%s)\n", status ? "TRUE" : "FALSE");
+
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+
+ if ( status) {
+ self->media_busy = TRUE;
+ irda_device_start_mbusy_timer( self);
+ DEBUG( 4, "Media busy!\n");
+ } else {
+ self->media_busy = FALSE;
+ del_timer( &self->media_busy_timer);
+ }
+}
+
+/*
+ * Function __irda_device_change_speed (self, speed)
+ *
+ * When this function is called, we will have a process context so its
+ * possible for us to sleep, wait or whatever :-)
+ */
+static void __irda_device_change_speed( struct irda_device *self, int speed)
+{
+ ASSERT( self != NULL, return;);
+
+ if ( self->magic != IRDA_DEVICE_MAGIC) {
+ DEBUG( 0, __FUNCTION__
+ "(), irda device is gone! Maybe you need to update "
+ "your irmanager and/or irattach!");
+
+ return;
+ }
+
+ /*
+ * Is is possible to change speed yet? Wait until the last byte
+ * has been transmitted.
+ */
+ if ( self->wait_until_sent) {
+ self->wait_until_sent( self);
+
+ if ( self->change_speed) {
+ self->change_speed( self, speed);
+
+ /* Update the QoS value only */
+ self->qos.baud_rate.value = speed;
+ }
+ } else {
+ DEBUG( 0, __FUNCTION__ "(), Warning, wait_until_sent() "
+ "is not implemented by the irda_device!\n");
+
+ }
+}
+
+/*
+ * Function irda_device_change_speed (self, speed)
+ *
+ * Change the speed of the currently used irda_device
+ *
+ */
+inline void irda_device_change_speed( struct irda_device *self, int speed)
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+
+ irda_execute_as_process( self,
+ (TODO_CALLBACK) __irda_device_change_speed,
+ speed);
+}
+
+inline int irda_device_is_media_busy( struct irda_device *self)
+{
+ ASSERT( self != NULL, return FALSE;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+
+ return self->media_busy;
+}
+
+inline int irda_device_is_receiving( struct irda_device *self)
+{
+ ASSERT( self != NULL, return FALSE;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+
+ if ( self->is_receiving)
+ return self->is_receiving( self);
+ else
+ return FALSE;
+}
+
+inline struct qos_info *irda_device_get_qos( struct irda_device *self)
+{
+ ASSERT( self != NULL, return NULL;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+
+ return &self->qos;
+}
+
+void irda_device_todo_expired( unsigned long data)
+{
+ struct irda_device *self = ( struct irda_device *) data;
+
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ /* Check that we still exist */
+ if ( !self || self->magic != IRDA_DEVICE_MAGIC) {
+ return;
+ }
+ __irda_device_change_speed( self, self->new_speed);
+}
+
+/*
+ * Function irda_device_start_todo_timer (self, timeout)
+ *
+ * Start todo timer. This function is used to delay execution of certain
+ * functions. Its implemented using timers since delaying a timer or a
+ * bottom halves function can be very difficult othervise.
+ *
+ */
+void irda_device_start_todo_timer( struct irda_device *self, int timeout)
+{
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+
+ del_timer( &self->todo_timer);
+
+ self->todo_timer.data = (unsigned long) self;
+ self->todo_timer.function = &irda_device_todo_expired;
+ self->todo_timer.expires = jiffies + timeout;
+
+ add_timer( &self->todo_timer);
+}
+
+static struct enet_statistics *irda_device_get_stats( struct device *dev)
+{
+ struct irda_device *priv = (struct irda_device *) dev->priv;
+
+ return &priv->stats;
+}
+
+/*
+ * Function irda_device_setup (dev)
+ *
+ * This function should be used by low level device drivers in a similar way
+ * as ether_setup() is used by normal network device drivers
+ */
+int irda_device_setup( struct device *dev)
+{
+ struct irda_device *self;
+
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( dev != NULL, return -1;);
+
+ self = (struct irda_device *) dev->priv;
+
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+ dev->get_stats = irda_device_get_stats;
+ dev->rebuild_header = irda_device_net_rebuild_header;
+ dev->set_config = irda_device_net_set_config;
+ dev->change_mtu = irda_device_net_change_mtu;
+ dev->hard_header = irda_device_net_hard_header;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+
+ dev->type = ARPHRD_IRDA;
+ dev->tx_queue_len = 10; /* Short queues in IrDA */
+
+ memcpy( dev->dev_addr, &self->irlap->saddr, 4);
+ memset( dev->broadcast, 0xff, 4);
+
+ dev->mtu = 2048;
+ dev->tbusy = 1;
+
+ dev_init_buffers( dev);
+
+ dev->flags = 0; /* IFF_NOARP | IFF_POINTOPOINT; */
+
+ return 0;
+}
+
+/*
+ * Function irda_device_net_rebuild_header (buff, dev, dst, skb)
+ *
+ *
+ *
+ */
+static int irda_device_net_rebuild_header( struct sk_buff *skb)
+{
+ DEBUG( 4, __FUNCTION__ "()\n");
+
+ return 0;
+}
+
+static int irda_device_net_hard_header (struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len)
+{
+ DEBUG( 0, __FUNCTION__ "()\n");
+
+ skb->mac.raw = skb->data;
+ /* skb_push(skb,PPP_HARD_HDR_LEN); */
+/* return PPP_HARD_HDR_LEN; */
+
+ return 0;
+}
+
+static int irda_device_net_set_config( struct device *dev, struct ifmap *map)
+{
+ DEBUG( 0, __FUNCTION__ "()\n");
+
+ return 0;
+}
+
+static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
+{
+ DEBUG( 0, __FUNCTION__ "()\n");
+
+ return 0;
+}
+
+/*
+ * Function irda_device_transmit_finished (void)
+ *
+ * Check if there is still some frames in the transmit queue for this
+ * device
+ *
+ */
+int irda_device_txqueue_empty( struct irda_device *self)
+{
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+ /* FIXME: check if this is the right way of doing it? */
+ if ( skb_queue_len( &self->netdev.qdisc->q))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Function irda_get_mtt (skb)
+ *
+ * Utility function for getting the
+ *
+ */
+__inline__ int irda_get_mtt( struct sk_buff *skb)
+{
+ return ((struct irlap_skb_cb *)(skb->cb))->mtt;
+}
+
+/*
+ * Function setup_dma (idev, buffer, count, mode)
+ *
+ * Setup the DMA channel
+ *
+ */
+void setup_dma( int channel, char *buffer, int count, int mode)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ disable_dma( channel);
+ clear_dma_ff( channel);
+ set_dma_mode( channel, mode);
+ set_dma_addr( channel, virt_to_bus(buffer));
+ set_dma_count( channel, count);
+ enable_dma( channel);
+
+ restore_flags(flags);
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * Function irlap_proc_read (buf, start, offset, len, unused)
+ *
+ * Give some info to the /proc file system
+ *
+ */
+int irda_device_proc_read( char *buf, char **start, off_t offset, int len,
+ int unused)
+{
+ struct irda_device *self;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ len = 0;
+
+ self = (struct irda_device *) hashbin_get_first( irda_device);
+ while ( self != NULL) {
+ len += sprintf( buf+len, "Irda_Device name: %s\n", self->name);
+ len += sprintf( buf+len, " bps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n");
+
+ len += sprintf( buf+len, " %d\t",
+ self->qos.baud_rate.value);
+ len += sprintf( buf+len, "%d\t",
+ self->qos.max_turn_time.value);
+ len += sprintf( buf+len, "%d\t",
+ self->qos.data_size.value);
+ len += sprintf( buf+len, "%d\t",
+ self->qos.window_size.value);
+ len += sprintf( buf+len, "%d\t",
+ self->qos.additional_bofs.value);
+ len += sprintf( buf+len, "%d\t",
+ self->qos.min_turn_time.value);
+ len += sprintf( buf+len, "%d",
+ self->qos.link_disc_time.value);
+ len += sprintf( buf+len, "\n");
+
+ self = (struct irda_device *) hashbin_get_next( irda_device);
+ }
+ restore_flags(flags);
+
+ return len;
+}
+
+#endif /* CONFIG_PROC_FS */
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov