]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Header-files cleanup and CAN queue edges and ends locking reimplemented.
authorppisa <ppisa>
Wed, 5 Nov 2003 02:44:22 +0000 (02:44 +0000)
committerppisa <ppisa>
Wed, 5 Nov 2003 02:44:22 +0000 (02:44 +0000)
The code has been updated and tested with 2.6.0-test9 as well.
Default asynchronous close does not wait for transmission of the
messages left in the Tx FIFOs. ENDS dispose is delayed in such case.
Virtual chip driver can model bus latency if nonzero baudrate is selected.

44 files changed:
lincan/include/can_queue.h
lincan/include/can_sysdep.h [new file with mode: 0644]
lincan/include/constants.h
lincan/include/devcommon.h
lincan/include/finish.h [new file with mode: 0644]
lincan/include/main.h
lincan/include/setup.h
lincan/src/Makefile
lincan/src/aim104.c
lincan/src/bfadcan.c
lincan/src/boardlist.c
lincan/src/can_quekern.c [new file with mode: 0644]
lincan/src/can_queue.c
lincan/src/cc_can104.c
lincan/src/close.c
lincan/src/devcommon.c
lincan/src/finish.c [new file with mode: 0644]
lincan/src/i82527.c
lincan/src/ioctl.c
lincan/src/irq.c
lincan/src/m437.c
lincan/src/main.c
lincan/src/modparms.c
lincan/src/nsi.c
lincan/src/open.c
lincan/src/pc_i03.c
lincan/src/pccan.c
lincan/src/pcccan.c
lincan/src/pcm3680.c
lincan/src/pikronisa.c
lincan/src/pip.c
lincan/src/proc.c
lincan/src/read.c
lincan/src/select.c
lincan/src/setup.c
lincan/src/sja1000.c
lincan/src/sja1000p.c
lincan/src/smartcan.c
lincan/src/ssv.c
lincan/src/template.c
lincan/src/virtual.c
lincan/src/write.c
lincan/utils/Makefile
lincan/utils/sendburst.c

index 15f898a5d06a4bcdf38b1fc86638148708f026ea..5951186166a81f846d9e5f6f6c25b6ce9d39f82c 100644 (file)
@@ -1,30 +1,9 @@
 #ifndef _CAN_QUEUE_H
 #define _CAN_QUEUE_H
 
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
 #include "./can.h"
 #include "./constants.h"
-
-/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
-   kernels need next definitions  too */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
-  #define wait_queue_head_t struct wait_queue *
-  #define wait_queue_t      struct wait_queue
-  #define init_waitqueue_head(queue_head) (*queue_head=NULL)
-  #define init_waitqueue_entry(qentry,qtask) \
-                        (qentry->next=NULL,qentry->task=qtask)
-  #define DECLARE_WAIT_QUEUE_HEAD(name) \
-        struct wait_queue * name=NULL
-  #define DECLARE_WAITQUEUE(wait, current) \
-        struct wait_queue wait = { current, NULL }
-  #define init_MUTEX(sem) (*sem=MUTEX)
-  #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-#endif /* 2.2.19 */
-
+#include "./can_sysdep.h"
 
 /**
  * struct canque_slot_t - one CAN message slot in the CAN FIFO queue 
@@ -83,6 +62,9 @@ struct canque_fifo_t {
 #define CAN_FIFOF_FULL_b       10
 #define CAN_FIFOF_EMPTY_b      9
 #define CAN_FIFOF_DEAD_b       8
+#define CAN_FIFOF_INACTIVE_b   7
+#define CAN_FIFOF_FREEONEMPTY_b        6
+#define CAN_FIFOF_READY_b      5
 
 #define CAN_FIFOF_DESTROY      (1<<CAN_FIFOF_DESTROY_b)
 #define CAN_FIFOF_ERROR                (1<<CAN_FIFOF_ERROR_b)
@@ -92,6 +74,9 @@ struct canque_fifo_t {
 #define CAN_FIFOF_FULL         (1<<CAN_FIFOF_FULL_b)
 #define CAN_FIFOF_EMPTY                (1<<CAN_FIFOF_EMPTY_b)
 #define CAN_FIFOF_DEAD         (1<<CAN_FIFOF_DEAD_b)
+#define CAN_FIFOF_INACTIVE     (1<<CAN_FIFOF_INACTIVE_b)
+#define CAN_FIFOF_FREEONEMPTY  (1<<CAN_FIFOF_FREEONEMPTY_b)
+#define CAN_FIFOF_READY                (1<<CAN_FIFOF_READY_b)
 
 #define canque_fifo_test_fl(fifo,fifo_fl) \
   test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
@@ -155,10 +140,11 @@ int canque_fifo_put_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slo
        if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
        *fifo->tail=slot;
        fifo->tail=&slot->next;
+       ret=0;
        if(canque_fifo_test_and_clear_fl(fifo,EMPTY))
          ret=CAN_FIFOF_EMPTY;  /* Fifo has been empty before put */
-       else 
-         ret=0;
+       if(canque_fifo_test_and_clear_fl(fifo,INACTIVE))
+         ret=CAN_FIFOF_INACTIVE; /* Fifo has been empty before put */
        spin_unlock_irqrestore(&fifo->fifo_lock, flags);
        return ret;
 }
@@ -312,6 +298,7 @@ struct canque_edge_t {
 
 /**
  * struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends)
+ * @ends_flags: this field holds flags describing state of the ENDS structure.
  * @active: the array of the lists of active edges directed to the ends structure
  *     with ready messages. The array is indexed by the edges priorities. 
  * @idle: the list of the edges directed to the ends structure with empty FIFOs.
@@ -337,6 +324,7 @@ struct canque_edge_t {
  * this structure.
  */
 struct canque_ends_t {
+       unsigned long ends_flags;
        struct list_head active[CANQUEUE_PRIO_NR];
        struct list_head idle;
        struct list_head inlist;
@@ -355,20 +343,24 @@ struct canque_ends_t {
                        struct chip_t *chip;
                } chipinfo;
        } endinfo;
+       struct list_head dead_peers;
 };
 
-#define CANQUEUE_NOTIFY_EMPTY 1        /* out -> in - all slots are processed by FIFO out side */
-#define CANQUEUE_NOTIFY_SPACE 2        /* out -> in - full state negated => there is space for new message */
-#define CANQUEUE_NOTIFY_PROC  3        /* in -> out - empty state negated => out side is requested to process slots */
-#define CANQUEUE_NOTIFY_NOUSR 4        /* called with some lock to prevent edge disappear */
-#define CANQUEUE_NOTIFY_DEAD  5        /*  */
-#define CANQUEUE_NOTIFY_ATACH 6        /*  */
-#define CANQUEUE_NOTIFY_FILTCH 7 /* filter changed */
+#define CANQUEUE_NOTIFY_EMPTY  1 /* out -> in - all slots are processed by FIFO out side */
+#define CANQUEUE_NOTIFY_SPACE  2 /* out -> in - full state negated => there is space for new message */
+#define CANQUEUE_NOTIFY_PROC   3 /* in -> out - empty state negated => out side is requested to process slots */
+#define CANQUEUE_NOTIFY_NOUSR  4 /* called with some lock to prevent edge disappear */
+#define CANQUEUE_NOTIFY_DEAD   5 /*  */
+#define CANQUEUE_NOTIFY_DEAD_WANTED 6 /*  */
+#define CANQUEUE_NOTIFY_ATTACH 7 /*  */
+#define CANQUEUE_NOTIFY_FILTCH 8 /* filter changed */
 #define CANQUEUE_NOTIFY_ERROR      0x10000 /* error notifiers */
 #define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */
 #define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
 #define CANQUEUE_NOTIFY_ERRTX_BUS  0x11003 /* tx bus error */
 
+#define CAN_ENDSF_DEAD (1<<0)
+
 /**
  * canque_notify_inends - request to send notification to the input ends
  * @qedge: pointer to the edge structure
@@ -481,6 +473,101 @@ int canque_set_filt(struct canque_edge_t *qedge,
        
 int canque_flush(struct canque_edge_t *qedge);
 
+int canqueue_disconnect_edge(struct canque_edge_t *qedge);
+
+int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+
+int canqueue_ends_init_gen(struct canque_ends_t *qends);
+
+
+/* edge reference and traversal functions */
+
+void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl);
+
+static inline
+void canque_edge_incref(struct canque_edge_t *edge)
+{
+       atomic_inc(&edge->edge_used);
+}
+
+static inline
+void canque_edge_decref(struct canque_edge_t *edge)
+{
+       unsigned long flags;
+       struct canque_ends_t *inends=edge->inends;
+       struct canque_ends_t *outends=edge->outends;
+       int dead_fl;
+       
+       spin_lock_irqsave(&inends->ends_lock, flags);
+       spin_lock(&outends->ends_lock);
+       if(atomic_dec_and_test(&edge->edge_used)) {
+               dead_fl=canque_fifo_test_and_set_fl(&edge->fifo,DEAD);
+               /*This should not be there, but it cannot be outside of the lock :-(*/
+               canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+               spin_unlock(&outends->ends_lock);
+               spin_unlock_irqrestore(&inends->ends_lock, flags);
+               canque_edge_do_dead(edge, dead_fl);
+       } else {
+               spin_unlock(&outends->ends_lock);
+               spin_unlock_irqrestore(&inends->ends_lock, flags);
+       }
+}
+
+static inline
+struct canque_edge_t *canque_first_inedge(struct canque_ends_t *qends)
+{
+       unsigned long flags;
+       struct list_head *entry;
+       struct canque_edge_t *edge;
+       
+       spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=qends->inlist.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               edge=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(edge);
+       } else {
+               edge=NULL;
+       }
+       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       return edge;
+}
+
+
+static inline
+struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct canque_edge_t *edge)
+{
+       unsigned long flags;
+       struct list_head *entry;
+       struct canque_edge_t *next;
+       
+       spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=edge->inpeers.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               next=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(next);
+       } else {
+               next=NULL;
+       }
+       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(edge);
+       return next;
+}
+
+#define canque_for_each_inedge(qends, edge) \
+           for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge))
+
+/* Linux kernel specific functions */
+
 struct canque_edge_t *canque_new_edge_kern(int slotsnr);
 
 int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
@@ -492,12 +579,11 @@ int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
 
 int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge);
 
-int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+int canqueue_ends_init_kern(struct canque_ends_t *qends);
 
-int canqueue_ends_init_gen(struct canque_ends_t *qends);
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync);
 
-int canqueue_ends_init_kern(struct canque_ends_t *qends);
+void canqueue_kern_initialize(void);
 
-int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync);
 
 #endif /*_CAN_QUEUE_H*/
diff --git a/lincan/include/can_sysdep.h b/lincan/include/can_sysdep.h
new file mode 100644 (file)
index 0000000..9e6adf5
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _CAN_SYSDEP_H
+#define _CAN_SYSDEP_H
+
+/*#define __NO_VERSION__*/
+/*#include <linux/module.h>*/
+
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+
+/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
+   kernels need next definitions  too */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
+  #define wait_queue_head_t struct wait_queue *
+  #define wait_queue_t      struct wait_queue
+  #define init_waitqueue_head(queue_head) (*queue_head=NULL)
+  #define init_waitqueue_entry(qentry,qtask) \
+                        (qentry->next=NULL,qentry->task=qtask)
+  #define DECLARE_WAIT_QUEUE_HEAD(name) \
+        struct wait_queue * name=NULL
+  #define DECLARE_WAITQUEUE(wait, current) \
+        struct wait_queue wait = { current, NULL }
+  #define init_MUTEX(sem) (*sem=MUTEX)
+  #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+#endif /* 2.2.19 */
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+
+#define MINOR_NR \
+       (MINOR(file->f_dentry->d_inode->i_rdev))
+
+#else /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+#define MINOR_NR \
+       (minor(file->f_dentry->d_inode->i_rdev))
+
+#endif /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
+  typedef void irqreturn_t;
+  #define IRQ_NONE
+  #define IRQ_HANDLED
+  #define IRQ_RETVAL(x)
+#endif /* <=2.5.67 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
+   #define can_synchronize_irq(irqnum) synchronize_irq()
+#else /* >=2.5.33 */
+   #define can_synchronize_irq synchronize_irq
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+  #define del_timer_sync del_timer
+#endif /* <2.4.0 */
+
+#endif /*_CAN_SYSDEP_H*/
index 2d86cc354c80db821dfa1143fc6a8ef4abd9fae7..6e716439cca227ce4b35d0db1fac233b11c18390 100644 (file)
@@ -33,6 +33,7 @@
 #define MAX_MSGOBJS 15
 #define MAX_TOT_MSGOBJS (MAX_TOT_CHIPS*MAX_MSGOBJS)
 #define MAX_BUF_LENGTH 64
+//#define MAX_BUF_LENGTH 4
 
 #define IE (1<<1)
 #define SIE (1<<2)
 #define OBJ_TX_LOCK (1<<3)
 
 /* These flags can be used for the chip_t structure flags data entry */
-#define CHIP_CONFIGURED (1<<0)
-#define CHIP_SEGMENTED (1<<1)
+#define CHIP_CONFIGURED  (1<<0)
+#define CHIP_SEGMENTED   (1<<1)
+#define CHIP_IRQ_SETUP   (1<<2)
 
 /* These flags can be used for the candevices_t structure flags data entry */
-#define PROGRAMMABLE_IRQ (1<<0)
+#define CANDEV_PROGRAMMABLE_IRQ (1<<0)
+#define CANDEV_IO_RESERVED     (1<<1)
 
 enum timing_BTR1 {
        MAX_TSEG1 = 15,
index e19471e123a7a98b93546603b13b441487007858..f49b2fec44ab09222fcca91799313fbdd7c92013 100644 (file)
@@ -6,14 +6,10 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
 #include "./can.h"
+#include "./can_sysdep.h"
 #include "./constants.h"
 #include "./can_queue.h"
 
 int canqueue_ends_init_chip(struct canque_ends_t *qends, struct chip_t *chip, struct msgobj_t *obj);
+int canqueue_ends_done_chip(struct canque_ends_t *qends);
diff --git a/lincan/include/finish.h b/lincan/include/finish.h
new file mode 100644 (file)
index 0000000..f980e3e
--- /dev/null
@@ -0,0 +1,13 @@
+/* finish.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+
+void msgobj_done(struct msgobj_t *obj);
+void canchip_done(struct chip_t *chip);
+void candevice_done(struct candevice_t *candev);
+void canhardware_done(struct canhardware_t *candev);
index 3bdc912e4ac0d96886ae5e88e000fd1b87320107..03ee97629b7e0dc384c7516ed0142fb0ffb6b8b0 100644 (file)
@@ -7,13 +7,9 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <asm/io.h>
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
 #include "./can.h"
 #include "./constants.h"
+#include "./can_sysdep.h"
 #include "./can_queue.h"
 
 #ifdef CAN_DEBUG
 
 #define CANMSG(fmt,args...) printk(KERN_ERR "can.o: " fmt,##args)
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7))
-
-#define MINOR_NR \
-       (MINOR(file->f_dentry->d_inode->i_rdev))
-
-#else /* Linux kernel > 2.5.7 */
-
-#define MINOR_NR \
-       (minor(file->f_dentry->d_inode->i_rdev))
-#endif /* Linux kernel > 2.5.7 */
-
-#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
-   typedef void irqreturn_t;
-   #define IRQ_NONE
-   #define IRQ_HANDLED
-   #define IRQ_RETVAL(x)
-#endif /* <=2.5.67 */
 
 /**
  * struct canhardware_t - structure representing pointers to all CAN boards
@@ -113,6 +92,7 @@ struct candevice_t {
  * @flags: chip flags: %CHIP_CONFIGURED .. chip is configured,
  *     %CHIP_SEGMENTED .. access to the chip is segmented (mainly for i82527 chips)
  * @clock: chip base clock frequency in Hz
+ * @baudrate: selected chip baudrate in Hz
  * @write_register: write chip register function copy -
  * @read_register: read chip register function copy
  * @sja_cdr_reg: SJA specific register -
@@ -153,7 +133,8 @@ struct chip_t {
        int chip_irq;
        unsigned long chip_base_addr;
        unsigned int flags;
-       int clock; /* Chip clock in Hz */
+       long clock; /* Chip clock in Hz */
+       long baudrate;
 
        void (*write_register)(unsigned char data,unsigned long address);
        unsigned (*read_register)(unsigned long address);
@@ -170,7 +151,7 @@ struct chip_t {
 
        struct candevice_t *hostdevice;
        
-       int max_objects;        /* 1 for sja1000, 15 for */
+       int max_objects;        /* 1 for sja1000, 15 for i82527 */
 };
 
 /**
@@ -186,6 +167,7 @@ struct chip_t {
  *     canque_test_outslot() call and is freed by canque_free_outslot()
  *     or rescheduled canque_again_outslot()
  * @tx_retry_cnt: transmission attempt counter
+ * @tx_timeout: can be used by chip driver to check for the transmission timeout
  * @rx_msg: temporary storage to hold received messages before
  *     calling to canque_filter_msg2edges()
  * @hostchip: pointer to the &chip_t structure this object belongs to
@@ -205,6 +187,7 @@ struct msgobj_t {
        struct canque_edge_t *tx_qedge;
        struct canque_slot_t *tx_slot;
        int tx_retry_cnt;
+       struct timer_list tx_timeout;
        
        struct canmsg_t rx_msg;
 
@@ -320,6 +303,7 @@ struct chipspecops_t {
 struct mem_addr {
        void *address;
        struct mem_addr *next;
+       size_t size;
 };
 
 /* Structure for the RTR queue */
@@ -333,7 +317,7 @@ struct rtr_id {
 extern int major;
 extern int minor[MAX_TOT_CHIPS];
 extern int extended;
-extern int baudrate;
+extern int baudrate[MAX_TOT_CHIPS];
 extern char *hw[MAX_HW_CARDS];
 extern int irq[MAX_IRQ];
 extern unsigned long io[MAX_HW_CARDS];
index 551adacbfd956906a48f668a5d60a9ae9092da60..686b83ab006940895b2b0b707ffbeb69fd53e1c5 100644 (file)
@@ -9,6 +9,6 @@
 
 int init_hw_struct(void);
 int list_hw(void);
-int add_mem_to_list(void *address_p);
-int del_mem_from_list(void *address_p);
-int del_mem_list(void);
+void *can_checked_malloc(size_t size);
+int can_checked_free(void *address_p);
+int can_del_mem_list(void);
index 1b1f8ef394f3ebcc8ad3b67058ee260f338d9dbb..7d87097e5213a37eb6b5c52a77daba556e19a6a0 100644 (file)
@@ -125,8 +125,9 @@ O_TARGET     = can.o
 endif
 # Regular object files
 O_OBJS      += $(SUPPORTED_CARDS:%=%.o)
-O_OBJS       += can_queue.o devcommon.o main.o modparms.o setup.o \
-               sja1000p.o sja1000.o i82527.o irq.o boardlist.o \
+O_OBJS       += can_queue.o can_quekern.o devcommon.o main.o modparms.o \
+               setup.o finish.o irq.o boardlist.o \
+               sja1000p.o sja1000.o i82527.o  \
                open.o proc.o close.o write.o read.o ioctl.o select.o
 # Objects with exported symbols (-DEXPORT_SYMTAB)
 OX_OBJS      = 
index 564809f6941627b7c933e25bc467ed4ada7238c9..63ef735a6186f5405ff7827bedfd66c13d381595 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/aim104.h"
 #include "../include/sja1000.h"
@@ -118,7 +113,7 @@ int aim104_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/template.c
@@ -129,7 +124,7 @@ int aim104_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=0;
         candev->nr_sja1000_chips=1;
        candev->nr_all_chips=1;
-       candev->flags &= ~PROGRAMMABLE_IRQ;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -207,7 +202,7 @@ int aim104_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function template_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 8eeaf3d814210e573652ff87f35bcec39e0b63f6..0f34958de9255d6f2497b1c063b8d9fed9031236 100644 (file)
  * possible to load the driver with the hardware option hw=bfadcan.
  */
 
-#define __NO_VERSION__ /* this is not a main module, do not include module info */
-
-#include <linux/autoconf.h>
-
-#include <linux/module.h>
-
-#include <linux/version.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
 
 #define WINDOWED_ACCESS
 
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/i82527.h"
 #include "../include/sja1000p.h"
 
+#define __NO_VERSION__
+#include <linux/module.h>
+
 long clock_freq;
 MODULE_PARM(clock_freq,"i");
 
@@ -157,7 +145,7 @@ int bfadcan_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/bfadcan.c
@@ -168,7 +156,7 @@ int bfadcan_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=NR_82527;
        candev->nr_sja1000_chips=NR_SJA1000;
        candev->nr_all_chips=NR_82527+NR_SJA1000;
-       candev->flags |= 0 /* PROGRAMMABLE_IRQ */ ;
+       candev->flags |= 0 /* CANDEV_PROGRAMMABLE_IRQ */ ;
 
        return 0;
 }
@@ -261,7 +249,7 @@ int bfadcan_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function bfadcan_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
@@ -286,7 +274,7 @@ int bfadcan_program_irq(struct candevice_t *candev)
 void bfadcan_write_register(unsigned char data, unsigned long address)
 {
 #ifdef WINDOWED_ACCESS
-       long flags;
+       unsigned long flags;
        spin_lock_irqsave(&bfadcan_win_lock,flags);
        outb(address&0x00ff,0x200);
        outb(data, 0x201);
@@ -309,7 +297,7 @@ void bfadcan_write_register(unsigned char data, unsigned long address)
 unsigned bfadcan_read_register(unsigned long address)
 {
 #ifdef WINDOWED_ACCESS
-       long flags;
+       unsigned long flags;
        int ret;
        spin_lock_irqsave(&bfadcan_win_lock,flags);
        outb(address&0x00ff,0x200);
index 569aab29ea0ab014ba9e2450de6891c1c1df8541..9075e7a76db70bf6934f08b9058eb174aba75f5e 100644 (file)
@@ -6,9 +6,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-#include <linux/version.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 
 #include ".supported_cards.h"
diff --git a/lincan/src/can_quekern.c b/lincan/src/can_quekern.c
new file mode 100644 (file)
index 0000000..4ffdaa0
--- /dev/null
@@ -0,0 +1,452 @@
+/* can_quekern.c - CAN message queues functions for the Linux kernel
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/can_queue.h"
+
+//#define CAN_DEBUG
+
+extern atomic_t edge_num_cnt;
+
+#ifdef CAN_DEBUG
+       #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
+       ##args)
+
+#else
+       #define DEBUGQUE(fmt,args...)
+#endif
+
+#define ERRMSGQUE(fmt,args...) printk(KERN_ERR "can_queue: " fmt,\
+       ##args)
+
+
+/* 
+ * Modifies Tx message processing 
+ *  0 .. local message processing disabled
+ *  1 .. local messages disabled by default but can be enabled by canque_set_filt
+ *  2 .. local messages enabled by default, can be disabled by canque_set_filt
+ */
+extern int processlocal;
+
+void canque_dead_func(unsigned long data);
+
+/* Support for dead ends structures left after client close */
+spinlock_t canque_dead_func_lock;
+LIST_HEAD(canque_dead_ends);
+/* retrieved by list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers) */
+LIST_HEAD(canque_dead_edges);
+/* retrieved by list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers) */
+DECLARE_TASKLET(canque_dead_tl, canque_dead_func, 0);
+/* activated by tasklet_schedule(&canque_dead_tl) */
+
+
+static inline
+struct canque_edge_t *canque_dead_edges_cut_first(void)
+{
+       unsigned long flags;
+       struct canque_edge_t *edge;
+       spin_lock_irqsave(&canque_dead_func_lock, flags);
+       if(list_empty(&canque_dead_edges))
+               edge=NULL;
+       else{
+               edge=list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers);
+               list_del(&edge->inpeers);
+       }
+       spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       return edge;
+}
+
+void canque_dead_func(unsigned long data)
+{
+       unsigned long flags;
+       struct canque_edge_t *qedge;
+       struct canque_ends_t *qends;
+       struct list_head *entry;
+       int i;
+
+       while((qedge=canque_dead_edges_cut_first())){
+               DEBUGQUE("edge %d disposed\n",qedge->edge_num);
+               kfree(qedge);
+       }
+       
+       spin_lock_irqsave(&canque_dead_func_lock, flags);
+       entry=canque_dead_ends.next;
+       spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+       while(entry!=&canque_dead_ends){
+               qends=list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers);
+               entry=entry->next;
+               if(!list_empty(&qends->inlist))
+                       continue;
+               if(!list_empty(&qends->idle))
+                       continue;
+               for(i=CANQUEUE_PRIO_NR;i--;)
+                       if(!list_empty(&qends->active[i]))
+                               continue;
+               spin_lock_irqsave(&canque_dead_func_lock, flags);
+               list_del(&qends->dead_peers);
+               spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+               DEBUGQUE("ends structure disposed\n");
+               kfree(qends);
+       }
+
+}
+
+
+void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
+{
+       unsigned long flags;
+       
+       if(dead_fl) return;
+       
+       if(canqueue_disconnect_edge(edge)<0){
+               ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n");
+               return;
+       }
+
+       spin_lock_irqsave(&canque_dead_func_lock, flags);
+       list_add(&edge->inpeers,&canque_dead_edges);
+       spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       tasklet_schedule(&canque_dead_tl);
+}
+
+
+
+/*if(qends->ends_flags & CAN_ENDSF_DEAD){
+       spin_lock_irqsave(&canque_dead_func_lock, flags);
+       list_del(&qends->dead_peers);
+       list_add(&qends->dead_peers,&canque_dead_ends);
+       spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       tasklet_schedule(&canque_dead_tl);
+}*/
+
+
+/**
+ * canqueue_notify_kern - notification callback handler for Linux userspace clients
+ * @qends: pointer to the callback side ends structure
+ * @qedge: edge which invoked notification 
+ * @what: notification type
+ */
+void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
+{
+       DEBUGQUE("canqueue_notify_kern for edge %d, use %d and event %d\n",
+                       qedge->edge_num,(int)atomic_read(&qedge->edge_used),what);
+       switch(what){
+               case CANQUEUE_NOTIFY_EMPTY:
+                       wake_up(&qends->endinfo.fileinfo.emptyq);
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
+                               canque_edge_decref(qedge);
+                       break;
+               case CANQUEUE_NOTIFY_SPACE:
+                       wake_up(&qends->endinfo.fileinfo.writeq);
+                       break;
+               case CANQUEUE_NOTIFY_PROC:
+                       wake_up(&qends->endinfo.fileinfo.readq);
+                       break;
+               case CANQUEUE_NOTIFY_NOUSR:
+                       wake_up(&qends->endinfo.fileinfo.readq);
+                       wake_up(&qends->endinfo.fileinfo.writeq);
+                       wake_up(&qends->endinfo.fileinfo.emptyq);
+                       break;
+               case CANQUEUE_NOTIFY_DEAD_WANTED:
+               case CANQUEUE_NOTIFY_DEAD:
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+                               canque_edge_decref(qedge);
+                       break;
+               case CANQUEUE_NOTIFY_ATTACH:
+                       break;
+       }
+}
+
+/**
+ * canqueue_ends_init_kern - Linux userspace clients specific ends initialization
+ * @qends: pointer to the callback side ends structure
+ */
+int canqueue_ends_init_kern(struct canque_ends_t *qends)
+{
+       canqueue_ends_init_gen(qends);
+       qends->context=NULL;
+       init_waitqueue_head(&qends->endinfo.fileinfo.readq);
+       init_waitqueue_head(&qends->endinfo.fileinfo.writeq);
+       init_waitqueue_head(&qends->endinfo.fileinfo.emptyq);
+       qends->notify=canqueue_notify_kern;
+       DEBUGQUE("canqueue_ends_init_kern\n");
+       return 0;
+}
+
+
+/**
+ * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to  allocated slot
+ * @cmd: command type for slot
+ * @id: communication ID of message to send into edge
+ * @prio: optional priority of message
+ *
+ * Same as canque_get_inslot4id(), except, that it waits for free slot
+ * in case, that queue is full. Function is specific for Linux userspace clients.
+ * Return Value: If there is no usable edge negative value is returned.
+ */
+int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio)
+{
+       int ret=-1;
+       DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
+       wait_event_interruptible((qends->endinfo.fileinfo.writeq), 
+               (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
+       return ret;
+}
+
+/**
+ * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to received slot
+ *
+ * The same as canque_test_outslot(), except it waits in the case, that there is
+ * no ready slot for given ends. Function is specific for Linux userspace clients.
+ * Return Value: Negative value informs, that there is no ready output
+ *     slot for given ends. Positive value is equal to the command
+ *     slot has been allocated by the input side.
+ */
+int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+{
+       int ret=-1;
+       DEBUGQUE("canque_get_outslot_wait_kern\n");
+       wait_event_interruptible((qends->endinfo.fileinfo.readq), 
+               (ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
+       return ret;
+}
+
+/**
+ * canque_sync_wait_kern - wait for all slots processing
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Functions waits for ends transition into empty state.
+ * Return Value: Positive value indicates, that edge empty state has been reached.
+ *     Negative or zero value informs about interrupted wait or other problem.
+ */
+int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+       int ret=-1;
+       DEBUGQUE("canque_sync_wait_kern\n");
+       wait_event_interruptible((qends->endinfo.fileinfo.emptyq), 
+               (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
+       return ret;
+}
+
+
+/**
+ * canque_new_edge_kern - allocate new edge structure in the Linux kernel context
+ * @slotsnr: required number of slots in the newly allocated edge structure
+ *
+ * Return Value: Returns pointer to allocated slot structure or %NULL if
+ *     there is not enough memory to process operation.
+ */
+struct canque_edge_t *canque_new_edge_kern(int slotsnr)
+{
+       struct canque_edge_t *qedge;
+       qedge = (struct canque_edge_t *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL);
+       if(qedge == NULL) return NULL;
+
+       memset(qedge,0,sizeof(struct canque_edge_t));
+       spin_lock_init(&qedge->fifo.fifo_lock);
+       if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){
+               kfree(qedge);
+               DEBUGQUE("canque_new_edge_kern failed\n");
+               return NULL;
+       }
+       atomic_set(&qedge->edge_used,1);
+       qedge->filtid = 0;
+       qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
+       qedge->edge_prio = 0;
+    #ifdef CAN_DEBUG
+       /* not exactly clean, but enough for debugging */
+       atomic_inc(&edge_num_cnt);
+       qedge->edge_num=atomic_read(&edge_num_cnt);
+    #endif /* CAN_DEBUG */
+       DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num);
+       return qedge;
+}
+
+/**
+ * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Same as canqueue_disconnect_edge(), but tries to wait for state with zero
+ * use counter.
+ * Return Value: Negative value means, that edge is used and cannot
+ *     be disconnected yet. Operation has to be delayed.
+ */
+int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+       canque_fifo_set_fl(&qedge->fifo,BLOCK);
+       DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
+       if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
+               canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
+               
+               if(atomic_read(&qedge->edge_used)>0)
+                       atomic_dec(&qedge->edge_used);
+
+               DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
+               wait_event((qends->endinfo.fileinfo.emptyq), 
+                       (canqueue_disconnect_edge(qedge)>=0));
+
+               /*set_current_state(TASK_UNINTERRUPTIBLE);*/
+               /*schedule_timeout(HZ);*/
+               return 0;
+       } else {
+               DEBUGQUE("canqueue_disconnect_edge_kern cannot set DEAD\n");
+               return -1;
+       }
+}
+
+
+int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list)
+{
+       struct canque_edge_t *edge;
+       unsigned long flags;
+       for(;;){
+               spin_lock_irqsave(&qends->ends_lock,flags);
+               if(list_empty(list)){
+                       spin_unlock_irqrestore(&qends->ends_lock,flags);
+                       return 0;
+               }
+               if(list == &qends->inlist)
+                       edge=list_entry(list->next,struct canque_edge_t,inpeers);
+               else
+                       edge=list_entry(list->next,struct canque_edge_t,outpeers);
+               atomic_inc(&edge->edge_used);
+               spin_unlock_irqrestore(&qends->ends_lock,flags);
+               if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
+                       /* Free edge memory */
+                       canque_fifo_done(&edge->fifo);
+                       kfree(edge);
+               }else{
+                       canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+                       canque_edge_decref(edge);
+                       DEBUGQUE("canqueue_disconnect_list_kern in troubles\n");
+                       DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags);
+                       return -1;
+               }
+       }
+}
+
+void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list)
+{
+       struct canque_edge_t *edge;
+       struct list_head *entry;
+       
+       /* has to be called with qends->ends_lock already locked */
+       list_for_each(entry,&qends->inlist){
+               if(list == &qends->inlist)
+                       edge=list_entry(list->next,struct canque_edge_t,inpeers);
+               else
+                       edge=list_entry(list->next,struct canque_edge_t,outpeers);
+               canque_fifo_set_fl(&edge->fifo,BLOCK);
+       }
+}
+
+int canqueue_ends_sync_all_kern(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *qedge;
+       
+       canque_for_each_inedge(qends, qedge){
+               DEBUGQUE("canque_sync_wait_kern called for edge %d\n",qedge->edge_num);
+               canque_sync_wait_kern(qends, qedge);
+       }
+       return 0;
+}
+
+int canqueue_ends_done_inends(struct canque_ends_t *qends, int send_rest)
+{
+       struct canque_edge_t *edge;
+       
+       canque_for_each_inedge(qends, edge){
+               canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+               if(send_rest){
+                       canque_edge_incref(edge);
+                       if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){
+                               if(!canque_fifo_test_fl(&edge->fifo, EMPTY))
+                                       continue;
+                               if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY))
+                                       continue;
+                       }
+                       canque_edge_decref(edge);
+               }
+       }
+       return list_empty(&qends->inlist)?0:1;
+}
+
+
+/**
+ * canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients
+ * @qends: pointer to ends structure
+ * @sync: flag indicating, that user wants to wait for processing of all remaining
+ *     messages
+ *
+ * Return Value: Function should be designed such way to not fail.
+ */
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync)
+{
+       unsigned long flags;
+       int i;
+       int delayed;
+
+       DEBUGQUE("canqueue_ends_dispose_kern\n");
+       spin_lock_irqsave(&qends->ends_lock,flags);
+       canqueue_block_list(qends, &qends->idle);
+       for(i=CANQUEUE_PRIO_NR;--i>=0;){
+               canqueue_block_list(qends, &qends->active[i]);
+       }
+       canqueue_block_list(qends, &qends->idle);
+       canqueue_block_list(qends, &qends->inlist);
+       spin_unlock_irqrestore(&qends->ends_lock,flags);
+
+       /*Wait for sending of all pending messages in the output FIFOs*/
+       if(sync)
+               canqueue_ends_sync_all_kern(qends);
+       
+       /* Finish all outgoing edges listed in inends */
+       delayed=canqueue_ends_done_inends(qends, 1);
+
+       delayed|=canqueue_disconnect_list_kern(qends, &qends->idle);
+       for(i=CANQUEUE_PRIO_NR;--i>=0;){
+               delayed|=canqueue_disconnect_list_kern(qends, &qends->active[i]);
+       }
+
+       wake_up(&qends->endinfo.fileinfo.readq);
+       wake_up(&qends->endinfo.fileinfo.writeq);
+       wake_up(&qends->endinfo.fileinfo.emptyq);
+
+       if(delayed){
+               spin_lock_irqsave(&canque_dead_func_lock, flags);
+               qends->ends_flags |= CAN_ENDSF_DEAD;
+               list_add(&qends->dead_peers,&canque_dead_ends);
+               spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+               tasklet_schedule(&canque_dead_tl);
+
+               DEBUGQUE("canqueue_ends_dispose_kern delayed\n");
+               return 1;
+       }
+
+       kfree(qends);
+       DEBUGQUE("canqueue_ends_dispose_kern finished\n");
+       return 0;
+}
+
+void canqueue_kern_initialize()
+{
+
+
+}
index 75853a961effa2bd10147e991660f952b5e5721a..6ee0550a550a45398b49c45b997736bb6f1e11b9 100644 (file)
@@ -6,16 +6,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/wait.h>
 #include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/can_queue.h"
 
 /* 
  */
 extern int processlocal;
 
-/*#define CAN_DEBUG*/
+atomic_t edge_num_cnt;
+
+//#define CAN_DEBUG
 
 #ifdef CAN_DEBUG
        #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
        ##args)
-       
-  atomic_t edge_num_cnt;
+
 #else
        #define DEBUGQUE(fmt,args...)
 #endif
 
 #define CANQUE_ROUNDROB 1
 
+
 /**
  * canque_fifo_flush_slots - free all ready slots from the FIFO
  * @fifo: pointer to the FIFO structure
@@ -134,15 +128,11 @@ int canque_get_inslot(struct canque_ends_t *qends,
        struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd)
 {
        int ret=-2;
-       unsigned long flags;
        struct canque_edge_t *edge;
        
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       if(!list_empty(&qends->inlist)){
-               edge=list_entry(qends->inlist.next,struct canque_edge_t,inpeers);
-               if(!canque_fifo_test_fl(&edge->fifo,BLOCK)&&!canque_fifo_test_fl(&edge->fifo,DEAD)){
-                       atomic_inc(&edge->edge_used);
-                       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       edge=canque_first_inedge(qends);
+       if(edge){
+               if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){
                        ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
                        if(ret>0){
                                *qedgep=edge;
@@ -150,12 +140,9 @@ int canque_get_inslot(struct canque_ends_t *qends,
                                return ret;
 
                        }
-                       spin_lock_irqsave(&qends->ends_lock, flags);
-                       if(atomic_dec_and_test(&edge->edge_used))
-                               canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
                }
+               canque_edge_decref(edge);
        }
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
        *qedgep=NULL;
        DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd);
        return ret;
@@ -183,14 +170,10 @@ int canque_get_inslot4id(struct canque_ends_t *qends,
        int cmd, unsigned long id, int prio)
 {
        int ret=-2;
-       unsigned long flags;
        struct canque_edge_t *edge, *bestedge=NULL;
-       struct list_head *entry;
        
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       list_for_each(entry,&qends->inlist){
-               edge=list_entry(entry,struct canque_edge_t,inpeers);
-               if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD))
+       canque_for_each_inedge(qends, edge){
+               if(canque_fifo_test_fl(&edge->fifo,BLOCK))
                        continue;
                if((id^edge->filtid)&edge->filtmask)
                        continue;
@@ -199,7 +182,9 @@ int canque_get_inslot4id(struct canque_ends_t *qends,
                                if (!edge->filtmask) continue;
                        } else {
                                if(edge->filtmask){
+                                       canque_edge_decref(bestedge);
                                        bestedge=edge;
+                                       canque_edge_incref(bestedge);
                                        continue;
                                }
                        }
@@ -208,23 +193,20 @@ int canque_get_inslot4id(struct canque_ends_t *qends,
                        } else {
                                if(bestedge->edge_prio<=prio) continue;
                        }
+                       canque_edge_decref(bestedge);
                }
                bestedge=edge;
+               canque_edge_incref(bestedge);
        }
        if((edge=bestedge)!=NULL){
-               atomic_inc(&edge->edge_used);
-               spin_unlock_irqrestore(&qends->ends_lock, flags);
                ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
                if(ret>0){
                        *qedgep=edge;
                        DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num);
                        return ret;
                }
-               spin_lock_irqsave(&qends->ends_lock, flags);
-               if(atomic_dec_and_test(&edge->edge_used))
-                       canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+               canque_edge_decref(bestedge);
        }
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
        *qedgep=NULL;
        DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio);
        return ret;
@@ -246,16 +228,12 @@ int canque_put_inslot(struct canque_ends_t *qends,
        struct canque_edge_t *qedge, struct canque_slot_t *slot)
 {
        int ret;
-       unsigned long flags;
        ret=canque_fifo_put_inslot(&qedge->fifo,slot);
        if(ret) {
                canque_activate_edge(qends,qedge);
                canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC);
        }
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(qedge);
        DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret);
        return ret;
 }
@@ -274,15 +252,11 @@ int canque_abort_inslot(struct canque_ends_t *qends,
        struct canque_edge_t *qedge, struct canque_slot_t *slot)
 {
        int ret;
-       unsigned long flags;
        ret=canque_fifo_abort_inslot(&qedge->fifo,slot);
        if(ret) {
                canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE);
        }
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(qedge);
        DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret);
        return ret;
 }
@@ -300,26 +274,19 @@ int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
 {
        int destnr=0;
        int ret;
-       unsigned long flags;
        unsigned long msgid;
        struct canque_edge_t *edge;
-       struct list_head *entry;
        struct canque_slot_t *slot;
        
        DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
                        msg->id, msg->flags);
        msgid = canque_filtid2internal(msg->id, msg->flags);
 
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       list_for_each(entry,&qends->inlist){
-               edge=list_entry(entry,struct canque_edge_t,inpeers);
-               if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD))
+       canque_for_each_inedge(qends, edge) {
+               if(canque_fifo_test_fl(&edge->fifo,BLOCK))
                        continue;
-               /* FIXME: the next comparison should be outside of ends lock */
                if((msgid^edge->filtid)&edge->filtmask)
                        continue;
-               atomic_inc(&edge->edge_used);
-               spin_unlock_irqrestore(&qends->ends_lock, flags);
                ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0);
                if(ret>0){
                        slot->msg=*msg;
@@ -331,11 +298,7 @@ int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
                        }
 
                }
-               spin_lock_irqsave(&qends->ends_lock, flags);
-               if(atomic_dec_and_test(&edge->edge_used))
-                       canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
        }
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
        DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr);
        return destnr;
 }
@@ -358,16 +321,28 @@ int canque_test_outslot(struct canque_ends_t *qends,
        unsigned long flags;
        int prio;
        struct canque_edge_t *edge;
+       int ret;
        
        spin_lock_irqsave(&qends->ends_lock, flags);
        for(prio=CANQUEUE_PRIO_NR;--prio>=0;){
-               if(!list_empty(&qends->active[prio])){
+               while(!list_empty(&qends->active[prio])){
                        edge=list_entry(qends->active[prio].next,struct canque_edge_t,outpeers);
-                       atomic_inc(&edge->edge_used);
-                       spin_unlock_irqrestore(&qends->ends_lock, flags);
-                       *qedgep=edge;
-                       DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
-                       return canque_fifo_test_outslot(&edge->fifo, slotp);
+                       if(!canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                               canque_edge_incref(edge);
+                               spin_unlock_irqrestore(&qends->ends_lock, flags);
+                               *qedgep=edge;
+                               DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
+                               ret=canque_fifo_test_outslot(&edge->fifo, slotp);
+                               if(ret>=0)
+                                       return ret;
+                               spin_lock_irqsave(&qends->ends_lock, flags);
+                       }
+                       spin_lock(&edge->fifo.fifo_lock);
+                       if(canque_fifo_test_and_set_fl(&edge->fifo,INACTIVE)) {
+                               list_del(&edge->outpeers);
+                               list_add(&edge->outpeers,&qends->idle);
+                       }
+                       spin_unlock(&edge->fifo.fifo_lock);
                }
        }
        spin_unlock_irqrestore(&qends->ends_lock, flags);
@@ -399,23 +374,20 @@ int canque_free_outslot(struct canque_ends_t *qends,
        if(ret&CAN_FIFOF_FULL)
                canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
        spin_lock_irqsave(&qends->ends_lock, flags);
-       if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB){
+       if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){
                spin_lock(&qedge->fifo.fifo_lock);
                if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
+                       canque_fifo_set_fl(&qedge->fifo,INACTIVE);
                        list_del(&qedge->outpeers);
                        list_add(&qedge->outpeers,&qends->idle);
-               }
-           #if CANQUE_ROUNDROB
-               else{
+               } else{
                        list_del(&qedge->outpeers);
                        list_add_tail(&qedge->outpeers,&qends->active[qedge->edge_prio]);
                }
-           #endif /*CANQUE_ROUNDROB*/
                spin_unlock(&qedge->fifo.fifo_lock);
        }
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
        spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(qedge);
        DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret);
        return ret;
 }
@@ -434,12 +406,8 @@ int canque_again_outslot(struct canque_ends_t *qends,
        struct canque_edge_t *qedge, struct canque_slot_t *slot)
 {
        int ret;
-       unsigned long flags;
        ret=canque_fifo_again_outslot(&qedge->fifo, slot);
-       spin_lock_irqsave(&qends->ends_lock, flags);
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
-       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(qedge);
        DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret);
        return ret;
 }
@@ -475,7 +443,7 @@ int canque_set_filt(struct canque_edge_t *qedge,
                canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH);
        }
        spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
-       if(!ret)canque_fifo_clear_fl(&qedge->fifo,BLOCK);
+       if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK);
        spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
        
        DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
@@ -534,155 +502,6 @@ int canqueue_ends_init_gen(struct canque_ends_t *qends)
 }
 
 
-/**
- * canqueue_notify_kern - notification callback handler for Linux userspace clients
- * @qends: pointer to the callback side ends structure
- * @qedge: edge which invoked notification 
- * @what: notification type
- */
-void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
-{
-       DEBUGQUE("canqueue_notify_kern for edge %d and event %d\n",qedge->edge_num,what);
-       switch(what){
-               case CANQUEUE_NOTIFY_EMPTY:
-                       wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
-                       break;
-               case CANQUEUE_NOTIFY_SPACE:
-                       wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
-                       break;
-               case CANQUEUE_NOTIFY_PROC:
-                       wake_up_interruptible(&qends->endinfo.fileinfo.readq);
-                       break;
-               case CANQUEUE_NOTIFY_NOUSR:
-                       wake_up_interruptible(&qends->endinfo.fileinfo.readq);
-                       wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
-                       wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
-                       break;
-               case CANQUEUE_NOTIFY_DEAD:
-                       if(atomic_read(&qedge->edge_used)>0)
-                               atomic_dec(&qedge->edge_used);
-                       break;
-               case CANQUEUE_NOTIFY_ATACH:
-                       atomic_inc(&qedge->edge_used);
-                       break;
-       }
-}
-
-/**
- * canqueue_ends_init_kern - Linux userspace clients specific ends initialization
- * @qends: pointer to the callback side ends structure
- */
-int canqueue_ends_init_kern(struct canque_ends_t *qends)
-{
-       canqueue_ends_init_gen(qends);
-       qends->context=NULL;
-       init_waitqueue_head(&qends->endinfo.fileinfo.readq);
-       init_waitqueue_head(&qends->endinfo.fileinfo.writeq);
-       init_waitqueue_head(&qends->endinfo.fileinfo.emptyq);
-       qends->notify=canqueue_notify_kern;
-       DEBUGQUE("canqueue_ends_init_kern\n");
-       return 0;
-}
-
-
-/**
- * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID
- * @qends: ends structure belonging to calling communication object
- * @qedgep: place to store pointer to found edge
- * @slotp: place to store pointer to  allocated slot
- * @cmd: command type for slot
- * @id: communication ID of message to send into edge
- * @prio: optional priority of message
- *
- * Same as canque_get_inslot4id(), except, that it waits for free slot
- * in case, that queue is full. Function is specific for Linux userspace clients.
- * Return Value: If there is no usable edge negative value is returned.
- */
-int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
-       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
-       int cmd, unsigned long id, int prio)
-{
-       int ret=-1;
-       DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
-       wait_event_interruptible((qends->endinfo.fileinfo.writeq), 
-               (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
-       return ret;
-}
-
-/**
- * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends
- * @qends: ends structure belonging to calling communication object
- * @qedgep: place to store pointer to found edge
- * @slotp: place to store pointer to received slot
- *
- * The same as canque_test_outslot(), except it waits in the case, that there is
- * no ready slot for given ends. Function is specific for Linux userspace clients.
- * Return Value: Negative value informs, that there is no ready output
- *     slot for given ends. Positive value is equal to the command
- *     slot has been allocated by the input side.
- */
-int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
-       struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
-{
-       int ret=-1;
-       DEBUGQUE("canque_get_outslot_wait_kern\n");
-       wait_event_interruptible((qends->endinfo.fileinfo.readq), 
-               (ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
-       return ret;
-}
-
-/**
- * canque_sync_wait_kern - wait for all slots processing
- * @qends: ends structure belonging to calling communication object
- * @qedge: pointer to edge
- *
- * Functions waits for ends transition into empty state.
- * Return Value: Positive value indicates, that edge empty state has been reached.
- *     Negative or zero value informs about interrupted wait or other problem.
- */
-int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
-{
-       int ret=-1;
-       DEBUGQUE("canque_sync_wait_kern\n");
-       wait_event_interruptible((qends->endinfo.fileinfo.emptyq), 
-               (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
-       return ret;
-}
-
-
-/**
- * canque_new_edge_kern - allocate new edge structure in the Linux kernel context
- * @slotsnr: required number of slots in the newly allocated edge structure
- *
- * Return Value: Returns pointer to allocated slot structure or %NULL if
- *     there is not enough memory to process operation.
- */
-struct canque_edge_t *canque_new_edge_kern(int slotsnr)
-{
-       struct canque_edge_t *qedge;
-       qedge = (struct canque_edge_t *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL);
-       if(qedge == NULL) return NULL;
-
-       memset(qedge,0,sizeof(struct canque_edge_t));
-       spin_lock_init(&qedge->fifo.fifo_lock);
-       if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){
-               kfree(qedge);
-               DEBUGQUE("canque_new_edge_kern failed\n");
-               return NULL;
-       }
-       atomic_set(&qedge->edge_used,0);
-       qedge->filtid = 0;
-       qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
-       qedge->edge_prio = 0;
-    #ifdef CAN_DEBUG
-       /* not exactly clean, but enough for debugging */
-       atomic_inc(&edge_num_cnt);
-       qedge->edge_num=atomic_read(&edge_num_cnt);
-    #endif /* CAN_DEBUG */
-       DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num);
-       return qedge;
-}
-
 /**
  * canqueue_connect_edge - connect edge between two communication entities
  * @qedge: pointer to edge
@@ -696,7 +515,7 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine
        unsigned long flags;
        if(qedge == NULL) return -1;
        DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num);
-       atomic_inc(&qedge->edge_used);
+       canque_edge_incref(qedge);
        spin_lock_irqsave(&inends->ends_lock, flags);
        spin_lock(&outends->ends_lock);
        spin_lock(&qedge->fifo.fifo_lock);
@@ -707,12 +526,10 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine
        spin_unlock(&qedge->fifo.fifo_lock);
        spin_unlock(&outends->ends_lock);
        spin_unlock_irqrestore(&inends->ends_lock, flags);
-       canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATACH);
-       
-       spin_lock_irqsave(&qedge->fifo.fifo_lock, flags);
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
-       spin_unlock_irqrestore(&qedge->fifo.fifo_lock, flags);
+       canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH);
+
+       if(canque_fifo_test_and_set_fl(&qedge->fifo, READY))
+               canque_edge_decref(qedge);
        return 0;
 }
 
@@ -720,8 +537,8 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine
  * canqueue_disconnect_edge - disconnect edge from communicating entities
  * @qedge: pointer to edge
  *
- * Return Value: Negative value means, that edge is used and cannot
- *     be disconnected. Operation has to be delayed.
+ * Return Value: Negative value means, that edge is used by somebody
+ *     other and cannot be disconnected. Operation has to be delayed.
  */
 int canqueue_disconnect_edge(struct canque_edge_t *qedge)
 {
@@ -752,113 +569,3 @@ int canqueue_disconnect_edge(struct canque_edge_t *qedge)
        return ret;
 }
 
-/**
- * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
- * @qends: ends structure belonging to calling communication object
- * @qedge: pointer to edge
- *
- * Same as canqueue_disconnect_edge(), but tries to wait for state with zero
- * use counter.
- * Return Value: Negative value means, that edge is used and cannot
- *     be disconnected yet. Operation has to be delayed.
- */
-int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
-{
-       canque_fifo_set_fl(&qedge->fifo,BLOCK);
-       DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
-       if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
-               canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
-               if(atomic_read(&qedge->edge_used)>0)
-                       atomic_dec(&qedge->edge_used);
-               DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
-               wait_event_interruptible((qends->endinfo.fileinfo.emptyq), 
-                       (canqueue_disconnect_edge(qedge)>=0));
-               return 0;
-       } else {
-               DEBUGQUE("canqueue_disconnect_edge_kern failed\n");
-               return -1;
-       }
-}
-
-
-int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list)
-{
-       struct canque_edge_t *edge;
-       unsigned long flags;
-       for(;;){
-               spin_lock_irqsave(&qends->ends_lock,flags);
-               if(list_empty(list)){
-                       spin_unlock_irqrestore(&qends->ends_lock,flags);
-                       return 0;
-               }
-               if(list == &qends->inlist)
-                       edge=list_entry(list->next,struct canque_edge_t,inpeers);
-               else
-                       edge=list_entry(list->next,struct canque_edge_t,outpeers);
-               atomic_inc(&edge->edge_used);
-               spin_unlock_irqrestore(&qends->ends_lock,flags);
-               if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
-                       /* Free edge memory */
-                       canque_fifo_done(&edge->fifo);
-                       kfree(edge);
-               }else{
-                       DEBUGQUE("canqueue_disconnect_list_kern in troubles\n");
-                       DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags);
-                       return -1;
-               }
-       }
-}
-
-void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list)
-{
-       struct canque_edge_t *edge;
-       struct list_head *entry;
-       
-       /* has to be called with qends->ends_lock already locked */
-       list_for_each(entry,&qends->inlist){
-               if(list == &qends->inlist)
-                       edge=list_entry(list->next,struct canque_edge_t,inpeers);
-               else
-                       edge=list_entry(list->next,struct canque_edge_t,outpeers);
-               canque_fifo_set_fl(&edge->fifo,BLOCK);
-       }
-}
-
-
-/**
- * canqueue_ends_done_kern - finalizing of the ends structure for Linux kernel clients
- * @qends: pointer to ends structure
- * @sync: flag indicating, that user wants to wait for processing of all remaining
- *     messages
- *
- * Return Value: Function should be designed such way to not fail.
- */
-int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync)
-{
-       unsigned long flags;
-       int i;
-
-       DEBUGQUE("canqueue_ends_done_kern\n");
-       spin_lock_irqsave(&qends->ends_lock,flags);
-       canqueue_block_list(qends, &qends->idle);
-       for(i=CANQUEUE_PRIO_NR;--i>=0;){
-               canqueue_block_list(qends, &qends->active[i]);
-       }
-       canqueue_block_list(qends, &qends->idle);
-       canqueue_block_list(qends, &qends->inlist);
-       spin_unlock_irqrestore(&qends->ends_lock,flags);
-
-       for(i=CANQUEUE_PRIO_NR;--i>=0;){
-               canqueue_disconnect_list_kern(qends, &qends->active[i]);
-       }
-       canqueue_disconnect_list_kern(qends, &qends->idle);
-       canqueue_disconnect_list_kern(qends, &qends->inlist);
-
-       wake_up_interruptible(&qends->endinfo.fileinfo.readq);
-       wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
-       wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
-       
-
-       return 0;
-}
-
index e0f47fe2d5f46602cb6f8a1e947a2bc9140b6ab0..9b8dd261fe325a9aba98897280a52372a9d699f4 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/cc_can104.h"
 #include "../include/i82527.h"
@@ -98,7 +93,7 @@ int cc104_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/template.c
@@ -109,7 +104,7 @@ int cc104_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=0;
        candev->nr_sja1000_chips=1;
         candev->nr_all_chips=1;
-       candev->flags &= ~PROGRAMMABLE_IRQ;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -188,7 +183,7 @@ int cc104_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function template_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index b1146be6a45aae584523b78f921616372f40673b..c42869e147355cd3f48b3f554736136b75431e9d 100644 (file)
@@ -7,24 +7,16 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h> 
-
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/close.h"
 #include "../include/i82527.h"
 #include "../include/setup.h"
 
+#define __NO_VERSION__
+#include <linux/module.h>
+
 int can_close(struct inode *inode, struct file *file)
 {
        struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
@@ -40,9 +32,8 @@ int can_close(struct inode *inode, struct file *file)
        qends = canuser->qends;
 
        list_del(&canuser->peers);
-       canqueue_ends_done_kern(qends, 1);
        canuser->qends = NULL;
-       kfree(qends);
+       canqueue_ends_dispose_kern(qends, file->f_flags & O_SYNC);
 
        kfree(canuser);
 
index 9cd29d00e2a398b101e278a430a4d4356ce868c6..dce205a620507805cf4ca1f3342041f820daeda8 100644 (file)
@@ -6,16 +6,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/wait.h>
 #include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/can_queue.h"
 #include "../include/main.h"
 #include "../include/devcommon.h"
@@ -30,18 +22,18 @@ void canqueue_notify_chip(struct canque_ends_t *qends, struct canque_edge_t *qed
                /*case CANQUEUE_NOTIFY_EMPTY:*/
                /*case CANQUEUE_NOTIFY_SPACE:*/
                /*case CANQUEUE_NOTIFY_NOUSR:
-                       wake_up_interruptible(&qends->endinfo.chipinfo.daemonq);
+                       wake_up(&qends->endinfo.chipinfo.daemonq);
                        break;*/
                case CANQUEUE_NOTIFY_PROC:
-                       /*wake_up_interruptible(&qends->endinfo.chipinfo.daemonq);*/
+                       /*wake_up(&qends->endinfo.chipinfo.daemonq);*/
                        chip->chipspecops->wakeup_tx(chip, obj);
                        break;
+               case CANQUEUE_NOTIFY_DEAD_WANTED:
                case CANQUEUE_NOTIFY_DEAD:
-                       if(atomic_read(&qedge->edge_used)>0)
-                               atomic_dec(&qedge->edge_used);
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+                               canque_edge_decref(qedge);
                        break;
-               case CANQUEUE_NOTIFY_ATACH:
-                       atomic_inc(&qedge->edge_used);
+               case CANQUEUE_NOTIFY_ATTACH:
                        break;
        }
 }
@@ -64,3 +56,7 @@ int canqueue_ends_init_chip(struct canque_ends_t *qends, struct chip_t *chip, st
 }
 
 
+int canqueue_ends_done_chip(struct canque_ends_t *qends)
+{
+       return 0;
+}
diff --git a/lincan/src/finish.c b/lincan/src/finish.c
new file mode 100644 (file)
index 0000000..a5cd8d1
--- /dev/null
@@ -0,0 +1,105 @@
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/devcommon.h"
+#include "../include/finish.h"
+#include "../include/setup.h"
+
+
+
+void msgobj_done(struct msgobj_t *obj)
+{
+       if(obj->qends) {
+               if(canqueue_ends_done_chip(obj->qends) < 0)
+                       CANMSG("msgobj_done: problem with chip queue ends\n");
+       }
+
+       if((obj->hostchip) && (obj->object>0)) {
+               if(obj->hostchip->msgobj[obj->object-1] == obj)
+                       obj->hostchip->msgobj[obj->object-1]=NULL;
+               else
+                       CANMSG("msgobj_done: not registered in the chip_t\n");
+               obj->hostchip=NULL;
+       }
+       
+       if((obj->minor>=0)) {
+               if(objects_p[obj->minor] == obj)
+                       objects_p[obj->minor] = NULL;
+               else
+                       CANMSG("msgobj_done: not registered as minor\n");
+       }
+       
+       del_timer_sync(&obj->tx_timeout);
+
+       if(obj->qends) {
+               can_checked_free(obj->qends);
+       }
+       obj->qends=NULL;
+}
+
+
+void canchip_done(struct chip_t *chip)
+{
+
+       int i;
+       struct msgobj_t *obj;
+
+       if((chip->hostdevice) && (chip->chip_idx>=0)) {
+               if(chip->hostdevice->chip[chip->chip_idx] == chip)
+                       chip->hostdevice->chip[chip->chip_idx] = NULL;
+               else
+                       CANMSG("canchip_done: not registered in hostdevice\n");
+       }
+
+       if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+               free_irq(chip->chip_irq, chip);
+               chip->flags &= ~CHIP_IRQ_SETUP;
+       }
+               
+       can_synchronize_irq(chip->chip_irq);
+       
+       for(i=0; i<chip->max_objects; i++){
+               if((obj=chip->msgobj[i])==NULL)
+                       continue;
+               msgobj_done(obj);
+               can_checked_free(obj);
+       }
+       
+       can_checked_free(chip->chipspecops);
+       chip->chipspecops=NULL;
+
+}
+
+void candevice_done(struct candevice_t *candev)
+{
+       int i;
+       struct chip_t *chip;
+       
+       for(i=0; i<candev->nr_all_chips; i++){
+               if((chip=candev->chip[i])==NULL)
+                       continue;
+               canchip_done(chip);
+               can_checked_free(chip);
+       
+       }
+       if(candev->flags & CANDEV_IO_RESERVED) {
+               candev->hwspecops->release_io(candev);
+               candev->flags &= ~CANDEV_IO_RESERVED;
+       }
+       can_checked_free(candev->hwspecops);
+       candev->hwspecops=NULL;
+}
+
+void canhardware_done(struct canhardware_t *canhw)
+{
+       int i;
+       struct candevice_t *candev;
+       
+       for(i=0; i<canhw->nr_boards; i++){
+               if((candev=canhw->candevice[i])==NULL)
+                       continue;
+               candevice_done(candev);
+               can_checked_free(candev);
+       }
+
+}
index ec99430e58ba7222c45e4d739de93551fa1d6c3b..cbd7870f74b2ecc746e5129fa325279a14ce5010 100644 (file)
@@ -7,14 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/i82527.h"
 
@@ -89,10 +83,10 @@ int i82527_chip_config(struct chip_t *chip)
        else
                DEBUGMSG("Could read back, hardware is probably configured correctly\n");
 
-       if (baudrate == 0)
-               baudrate=1000;
+       if (chip->baudrate == 0)
+               chip->baudrate=1000000;
 
-       if (i82527_baud_rate(chip,baudrate*1000,chip->clock,0,75,0)) {
+       if (i82527_baud_rate(chip,chip->baudrate,chip->clock,0,75,0)) {
                CANMSG("Error configuring baud rate\n");
                return -ENODEV;
        }
@@ -563,7 +557,7 @@ void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj,
        spin_unlock(&hardware_p->rtr_lock);
 
        if (waitqueue_active(&rtr_search->rtr_wq))
-               wake_up_interruptible(&rtr_search->rtr_wq);
+               wake_up(&rtr_search->rtr_wq);
 }
 
 int i82527_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
index 08b3aa0aa2646cfbf6fec0e9bf9664e7556bdfda..38743fabbac9bd5805db4b8fd38d9b85b70a0302 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/ioctl.h"
 #include "../include/i82527.h"
index 1623ce8ea38617209d69a1206778cd3df6a34452..e48db31691f1452c63a84b4ac21324fd9f5be6c2 100644 (file)
@@ -7,17 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/irq.h"
 
index b5349b8265b5b39f626454e28fb31ff052233f32..6fa87e7f540a5656b4a741499eedd0bb514de4e0 100644 (file)
  *
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/m437.h"
 #include "../include/i82527.h"
@@ -150,7 +145,7 @@ int m437_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/m437.c
@@ -162,7 +157,7 @@ int m437_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=1;
        candev->nr_sja1000_chips=0;
         candev->nr_all_chips=1;
-       candev->flags &= ~PROGRAMMABLE_IRQ;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
        /* The M437 has no programmable IRQ */
 
        return 0;
@@ -245,7 +240,7 @@ int m437_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function m437_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 1e84d34a96bccf6f08dcc92475f7f3180fbeb1c8..a1b6631289049175931e213146d49fd2a8fcb759 100644 (file)
 #include <linux/wrapper.h>
 #endif
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
-
 #if !defined (__GENKSYMS__) 
 #if (defined (MODVERSIONS) && !defined(NOVER))
 #include <linux/modversions.h>
@@ -45,6 +39,8 @@
 #include <linux/miscdevice.h>
 #endif
 
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/modparms.h"
 #include "../include/devcommon.h"
@@ -57,6 +53,7 @@
 #include "../include/irq.h"
 #include "../include/ioctl.h"
 #include "../include/write.h"
+#include "../include/finish.h"
 
 #define EXPORT_SYMTAB
 
@@ -70,8 +67,8 @@ int extended=0;
 MODULE_PARM(extended,"1i");
 int pelican=0;
 MODULE_PARM(pelican,"1i");
-int baudrate=0;
-MODULE_PARM(baudrate,"1i");
+int baudrate[MAX_TOT_CHIPS];
+MODULE_PARM(baudrate, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i");
 char *hw[MAX_HW_CARDS]={NULL,};
 MODULE_PARM(hw, "1-" __MODULE_STRING(MAX_HW_CARDS)"s");
 int irq[MAX_IRQ]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
@@ -146,12 +143,15 @@ EXPORT_SYMBOL(can_fops);
 
 int init_module(void)
 {
-       int res=0,i=0;
+       int res=0,i=0, j;
        struct candevice_t *candev;
+       struct chip_t *chip;
 
        if (parse_mod_parms())
                return -EINVAL;
 
+       canqueue_kern_initialize();
+
        if (init_hw_struct())
                return -ENODEV;
 
@@ -169,6 +169,7 @@ int init_module(void)
                candev=hardware_p->candevice[i];
                if (candev->hwspecops->request_io(candev)) 
                        goto memory_error;
+               candev->flags|=CANDEV_IO_RESERVED;
        }
 
        for (i=0; i<hardware_p->nr_boards; i++) {
@@ -180,20 +181,23 @@ int init_module(void)
        spin_lock_init(&hardware_p->rtr_lock);
        hardware_p->rtr_queue=NULL;
 
-       i=0;
-       while ( (chips_p[i] != NULL) && (i < MAX_TOT_CHIPS) ) {
-               if (chips_p[i]->chipspecops->irq_handler) {
-                       if (request_irq(chips_p[i]->chip_irq,chips_p[i]->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chips_p[i]))
-                               goto interrupt_error;
-                       else
-                               DEBUGMSG("Registered interrupt %d\n",chips_p[i]->chip_irq);
-               }
-               i++;
-       }
-
        for (i=0; i<hardware_p->nr_boards; i++) {
                candev=hardware_p->candevice[i];
-               if (candev->flags & PROGRAMMABLE_IRQ)
+               for(j=0; j<candev->nr_all_chips; j++) {
+                       if((chip=candev->chip[j])==NULL)
+                               continue;
+                       if(!chip->chipspecops->irq_handler)
+                               continue;
+                       
+                       if (request_irq(chip->chip_irq,chip->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chip))
+                               goto interrupt_error;
+                       else {
+                               DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
+                               chip->flags |= CHIP_IRQ_SETUP;
+                       }
+               }
+               
+               if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
                        if (candev->hwspecops->program_irq(candev))
                                goto interrupt_error;
        }
@@ -238,18 +242,13 @@ int init_module(void)
                goto memory_error;
 
        memory_error: ;
-               for (i=0; i<hardware_p->nr_boards; i++) {
-                       candev=hardware_p->candevice[i];
-                       candev->hwspecops->release_io(candev);
-               }
-               goto register_error;
+               canhardware_done(hardware_p);
 
-       register_error: ;
                res=unregister_chrdev(major,DEVICE_NAME);
                if (res<0)
                        CANMSG("Error unloading CAN driver, error: %d\n",res);
                else
-                       CANMSG("Successfully unloaded CAN driver.\n");
+                       CANMSG("No CAN devices or driver setup error.\n");
                return -ENODEV;
 
 }
@@ -257,7 +256,6 @@ int init_module(void)
 void cleanup_module(void)
 {
        int res=0,i=0;
-       struct candevice_t *candev;
 
 #ifdef CONFIG_PROC_FS
        if (can_delete_procdir())
@@ -278,19 +276,10 @@ void cleanup_module(void)
            #endif
                }
 #endif
-        i=0;
-       while ( (chips_p[i] != NULL) & (i < MAX_TOT_CHIPS) ) {
-               if(chips_p[i]->chipspecops->irq_handler)
-                       free_irq(chips_p[i]->chip_irq, chips_p[i]);
-               i++;
-       }
 
-       for (i=0; i<hardware_p->nr_boards; i++){ 
-               candev=hardware_p->candevice[i];
-               candev->hwspecops->release_io(candev);
-       }
+       canhardware_done(hardware_p);
 
-       if ( del_mem_list() ) 
+       if ( can_del_mem_list() ) 
                CANMSG("Error deallocating memory\n");
 
        res=unregister_chrdev(major,DEVICE_NAME);
index 1608bd2d080b8af3009f55c692fd4028561383da..9e8b20e314adc88f7a456a3ff67bc3cfb3bec5b1 100644 (file)
@@ -8,11 +8,8 @@
  */
 
 
-#include <linux/autoconf.h>
-
-#include <linux/string.h>
-#include <linux/fs.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/modparms.h"
 
index 289a1edad606d8d925b0d8f6e9193deb3599e321..aeef3925f94edadd86046965193ec81841a73929 100644 (file)
@@ -7,14 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/nsi.h"
 #include "../include/i82527.h"
@@ -96,7 +90,7 @@ int nsi_reset(struct candevice_t *candev)
  * RESET_ADDR represents the io-address of the hardware reset register.
  * NR_82527 represents the number of intel 82527 chips on the board.
  * NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  */
 #define RESET_ADDR 0x02
@@ -109,7 +103,7 @@ int nsi_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=1;
        candev->nr_sja1000_chips=0;
         candev->nr_all_chips=1;
-       candev->flags |= PROGRAMMABLE_IRQ;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -162,7 +156,7 @@ int nsi_init_obj_data(struct chip_t *chip, int objnr)
 
 /* The function template_program_irq is used for hardware that uses programmable
  * interrupts. If your hardware doesn't use programmable interrupts you should
- * not set the candevices_t->flags entry to PROGRAMMABLE_IRQ and leave this
+ * not set the candevices_t->flags entry to CANDEV_PROGRAMMABLE_IRQ and leave this
  * function unedited. Again this function is hardware specific so there's no
  * example code.
  */
index e980f1613770c43486356f363203408733c8cb15..38ee4d4c8d91ba4b16044379bf024b8ba020f1e8 100644 (file)
@@ -7,30 +7,23 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h> 
-
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/open.h"
 #include "../include/i82527.h"
 #include "../include/setup.h"
 
+#define __NO_VERSION__
+#include <linux/module.h>
+
 int can_open(struct inode *inode, struct file *file)
 {
        struct msgobj_t *obj;
        struct chip_t *chip;
        struct canuser_t *canuser;
        struct canque_ends_t *qends;
+       struct canque_edge_t *edge;
 
        if ( ((obj=objects_p[MINOR_NR]) == NULL) || 
                        ((chip=objects_p[MINOR_NR]->hostchip) == NULL) ) {
@@ -71,11 +64,14 @@ int can_open(struct inode *inode, struct file *file)
        
        list_add(&canuser->peers, &obj->obj_users);
 
-       if(canqueue_connect_edge(canque_new_edge_kern(MAX_BUF_LENGTH),
-               canuser->qends, obj->qends)<0) goto no_qedge;
+       if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
+               canuser->qends, obj->qends)<0) goto no_tx_qedge;
 
        if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH),
-               obj->qends, canuser->qends)<0) goto no_qedge;
+               obj->qends, canuser->qends)<0) goto no_rx_qedge;
+       /*FIXME: more generic model should be used there*/
+       canque_edge_decref(canuser->rx_edge0);
+       canque_edge_decref(edge);
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
        MOD_INC_USE_COUNT;
@@ -83,12 +79,13 @@ int can_open(struct inode *inode, struct file *file)
 
        return 0;
        
-    no_qedge:
+    no_rx_qedge:
+       canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+       canque_edge_decref(edge);
+    no_tx_qedge:
        list_del(&canuser->peers);
-       canqueue_ends_done_kern(qends, 1);
        canuser->qends = NULL;
-       kfree(qends);
-       obj->qends = NULL;
+       canqueue_ends_dispose_kern(qends, 1);
 
     no_qends:
        kfree(canuser);
index daec69c4f2185f111766bea3a6fb18d59a1f6d64..1e2c93388031ed5807aa26c47f9055febbccd54a 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pc-i03.h"
 #include "../include/sja1000.h"
@@ -127,7 +122,7 @@ int pci03_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/pc-i03.c
@@ -215,7 +210,7 @@ int pci03_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function pci03_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 06e9e05971b751712ec371430860c0d867744d73..8745404147e7fd5ed733519ff5d73d949a60554c 100644 (file)
@@ -7,14 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pccan.h"
 #include "../include/i82527.h"
@@ -228,7 +222,7 @@ int pccanq_reset(struct candevice_t *candev)
 int pccan_init_hw_data(struct candevice_t *candev)
 {
        candev->res_addr=candev->io_addr+0x6001;
-       candev->flags |= PROGRAMMABLE_IRQ;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
 
        if (!strcmp(candev->hwname,"pccan-q")) {
                candev->nr_82527_chips=2;
index 0ca6f284ef16f069ee7fc851359ee1faa2050591..6f7b5766fbd47ad0963973c17c119110f3034ebc 100644 (file)
  * You can probably find more information at http://www.gespac.com
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pcccan.h"
 #include "../include/i82527.h"
@@ -141,7 +134,7 @@ int pcccan_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/pcccan.c
@@ -152,7 +145,7 @@ int pcccan_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=NR_82527;
        candev->nr_sja1000_chips=NR_SJA1000;
         candev->nr_all_chips=NR_82527+NR_SJA1000;
-       candev->flags &= ~PROGRAMMABLE_IRQ;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -237,7 +230,7 @@ int pcccan_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function pcccan_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 22330cb81b6f6e9ebb990b7d173501a00aef691f..4be3dd2515ca69a199e34f608e6a579ffe0139b1 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pcm3680.h"
 #include "../include/i82527.h"
@@ -129,7 +124,7 @@ int pcm3680_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/template.c
@@ -140,7 +135,7 @@ int pcm3680_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=NR_82527;
        candev->nr_sja1000_chips=NR_SJA1000;
        candev->nr_all_chips=NR_82527+NR_SJA1000;
-       candev->flags &= ~PROGRAMMABLE_IRQ;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -221,7 +216,7 @@ int pcm3680_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function template_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index a0a6d071fec1b767be4b2f118c09afbe043446e2..117560c96abeedc16d5e343add136f744712b8c6 100644 (file)
@@ -7,13 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pikronisa.h"
 #include "../include/i82527.h"
@@ -133,7 +128,7 @@ int pikronisa_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/pikronisa.c
@@ -144,7 +139,7 @@ int pikronisa_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=0;
        candev->nr_sja1000_chips=1;
        candev->nr_all_chips=1;
-       candev->flags |= PROGRAMMABLE_IRQ*0;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
 
        return 0;
 }
@@ -227,7 +222,7 @@ int pikronisa_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function pikronisa_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 72ede897e6318b4995ff387c2fad177233b3ca22..3e1984c67d3898e56f26cbddaa1e329175296f7c 100644 (file)
@@ -7,14 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/pip.h"
 #include "../include/i82527.h"
@@ -125,7 +119,7 @@ int pip_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=1;
        candev->nr_sja1000_chips=0;
        candev->nr_all_chips=1;
-       candev->flags |= PROGRAMMABLE_IRQ;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
index fb573be8cdfb99fdddeeda94810a9f5d376b8911..254aabcac3feb7944d39439dc17d6a15a662b401 100644 (file)
@@ -7,25 +7,15 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#include <linux/kernel.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/proc_fs.h>
-#include <linux/version.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/proc.h"
 #include "../include/setup.h"
 
+#define __NO_VERSION__
+#include <linux/module.h>
+
 int add_channel_to_procdir(struct candevice_t *candev);
 int remove_channel_from_procdir(void);
 int add_object_to_procdir(int chip_nr);
@@ -57,8 +47,8 @@ static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
 {
        struct proc_dir_entry *new_entry = NULL;
 
-       new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct 
-                                               proc_dir_entry), GFP_KERNEL);
+       new_entry = (struct proc_dir_entry *) 
+                       can_checked_malloc(sizeof(struct proc_dir_entry));
        if (new_entry == NULL)
                return NULL;
 
@@ -81,8 +71,7 @@ int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *par
 {
        if (del != NULL) {
                proc_unregister(parent, del->low_ino);
-               kfree(del);
-               del = NULL;
+               can_checked_free(del);
                return 0;
        }
        else return -ENODEV;
@@ -136,11 +125,9 @@ int add_channel_to_procdir(struct candevice_t *candev)
        for (i=0; i < candev->nr_all_chips; i++) {
 
                base->channel[cc] = (struct channelproc_t *)
-                       kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
+                       can_checked_malloc(sizeof(struct channelproc_t));
                if (base->channel[cc] == NULL)
                        return -ENOMEM;
-               else if (add_mem_to_list(base->channel[cc]))
-                       return -ENOMEM;
 
                sprintf(base->channel[cc]->ch_name, "channel%d",cc);
                                                
@@ -195,13 +182,10 @@ int add_object_to_procdir(int chip_nr)
 
        for (i=0; i<max_objects; i++) {
                base->channel[chip_nr]->object[i] = (struct objectproc_t *)
-                       kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
-                               
-                               
+                       can_checked_malloc(sizeof(struct objectproc_t));
+
                if (base->channel[chip_nr]->object[i] == NULL)
                        return -ENOMEM;
-               else if (add_mem_to_list( base->channel[chip_nr]->object[i]))
-                       return -ENOMEM;
 
                sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
                sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
index b1798974bc43c948b7185a7fefe67e6e267dbdf5..56cb1d5788c876cc3e1035108a1918572c748c49 100644 (file)
@@ -7,21 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#define __NO_VERSION__
-#include <linux/module.h> 
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/version.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/read.h"
 #include "../include/ioctl.h"
index efdb212010e37e2372df0c27bb59df8a7ce59a7c..79d97fcac4b75e275b997ee30f04c97fde70206e 100644 (file)
@@ -7,12 +7,11 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
 
-#include <linux/version.h>
 #include <linux/poll.h>
-
-#include "../include/main.h"
 #include "../include/select.h"
 
 unsigned int can_poll(struct file *file, poll_table *wait)
index 49b43153994e672d3dd04fc5e16f7286f437d9e2..57883ce39533747aa3c0876a63c922dd456dd057 100644 (file)
@@ -7,23 +7,12 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/fs.h>
-#include <linux/ioport.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/devcommon.h"
 #include "../include/setup.h"
+#include "../include/finish.h"
 
 extern int sja1000_register(struct chipspecops_t *chipspecops);
 extern int sja1000p_register(struct chipspecops_t *chipspecops);
@@ -35,79 +24,79 @@ int init_chip_struct(struct candevice_t *candev);
 int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase);
 int init_chipspecops(struct candevice_t *candev, int chipnr);
 
-int add_mem_to_list(void *address_p)
+void *can_checked_malloc(size_t size)
 {
        struct mem_addr *mem_new;
+       void *address_p;
+       
+       address_p=kmalloc(size,GFP_KERNEL);
+       if(address_p == NULL) {
+               CANMSG("can_checked_malloc: out of the memory\n");
+               return NULL;
+       }
 
 #ifdef DEBUG_MEM
-       DEBUGMSG("add_mem_to_list %p, mem_head=%p\n",address_p, mem_head);
-       return 0;
+       DEBUGMSG("can_checked_malloc: allocated %d bytes at %p, mem_head=%p\n",
+                       (int)size, address_p, mem_head);
 #endif
 
        mem_new=(struct mem_addr *)kmalloc(sizeof(struct mem_addr),GFP_KERNEL);
        if (mem_new == NULL) {
-               CANMSG("Memory list error.\n");
-               return -ENOMEM;
+               CANMSG("can_checked_malloc: memory list allocation error.\n");
+               kfree(address_p);
+               return NULL;
        }
        mem_new->next=mem_head;
        mem_new->address=address_p;
+       mem_new->size=size;
        mem_head=mem_new;
 
-       return 0;
+       return address_p;
 }
 
-int del_mem_from_list(void *address_p)
+int can_checked_free(void *address_p)
 {
-       struct mem_addr *mem_search=NULL;
-       struct mem_addr *mem_delete=NULL;
+       struct mem_addr **mem_pptr;
+       struct mem_addr *mem_del=NULL;
 
 #ifdef DEBUG_MEM
-       DEBUGMSG("del_mem_from_list %p, mem_head=%p\n", address_p, mem_head);
-       return 0;
+       DEBUGMSG("can_checked_free %p, mem_head=%p\n", address_p, mem_head);
 #endif
-       if(mem_head == NULL) {
-               CANMSG("del_mem_from_list: mem_head == NULL address_p=%p!\n",
-                               address_p);
-               return 0;
-       }
-
-       mem_search = mem_head;
 
-       if (mem_head->address == address_p) {
-               kfree(mem_head->address);
-               mem_head=mem_head->next;
-               kfree(mem_search);
-       }
-       else {
-               while (mem_search->next->address != address_p)
-                       mem_search=mem_search->next;
-               kfree(mem_search->next->address);               
-               mem_delete=mem_search->next;
-               mem_search->next=mem_search->next->next;
-               kfree(mem_delete);
+       for(mem_pptr = &mem_head; (mem_del = *mem_pptr); mem_pptr = &mem_del->next) {
+               if (mem_del->address != address_p)
+                       continue;
+               *mem_pptr=mem_del->next;
+               kfree(mem_del);
+               kfree(address_p);
+               return 0;
        }
-       return 0;
+       
+       CANMSG("can_checked_free: address %p not found on the mem list\n", address_p);
+       
+       kfree(address_p);
+       return -1;
 }
 
 
-int del_mem_list(void)
+int can_del_mem_list(void)
 {
-       struct mem_addr *mem_old;
+       struct mem_addr *mem;
 
 #ifdef DEBUG_MEM
-       DEBUGMSG("del_mem_list, mem_head=%p\n", mem_head);
-       return 0;
+       DEBUGMSG("can_del_mem_list, mem_head=%p\n", mem_head);
 #endif
        if(mem_head == NULL) {
-               CANMSG("del_mem_list: mem_head == NULL!\n");
+               CANMSG("can_del_mem_list: no entries on the list - OK\n");
                return 0;
        }
 
-       while (mem_head->next != NULL) {
-               mem_old=mem_head;
-               kfree(mem_old->address);
-               mem_head=mem_old->next;
-               kfree(mem_old);
+       while((mem=mem_head) != NULL) {
+               mem_head=mem->next;
+               CANMSG("can_del_mem_list: deleting %p with size %d\n",
+                       mem->address, (int)mem->size);
+               kfree(mem->address);
+               kfree(mem);
        }
        
        return 0;
@@ -189,13 +178,11 @@ int init_hw_struct(void)
 int init_device_struct(int card)
 {
        struct candevice_t *candev;
+       int ret;
        
-       candev=(struct candevice_t *)kmalloc(sizeof(struct candevice_t),GFP_KERNEL);
+       candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t));
        if (candev==NULL)
                return -ENOMEM;
-       else
-               if ( add_mem_to_list(candev) )
-                       return -ENOMEM;
 
         memset(candev, 0, sizeof(struct candevice_t));
 
@@ -208,24 +195,36 @@ int init_device_struct(int card)
        candev->io_addr=io[card];
        candev->dev_base_addr=io[card];
 
-       candev->hwspecops=(struct hwspecops_t *)kmalloc(sizeof(struct hwspecops_t),GFP_KERNEL);
+       candev->hwspecops=(struct hwspecops_t *)can_checked_malloc(sizeof(struct hwspecops_t));
        if (candev->hwspecops==NULL)
-               return -ENOMEM;
-       else
-               if ( add_mem_to_list(candev->hwspecops) )
-                       return -ENOMEM;
+               goto error_nomem;
+
        memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
 
        if (init_hwspecops(candev))
-               return -ENODEV;
+               goto error_nodev;
 
        if (candev->hwspecops->init_hw_data(candev))
-               return -ENODEV;
+               goto error_nodev;
 
        if (init_chip_struct(candev))
-               return -ENODEV;
+               goto error_nodev;
 
        return 0;
+
+    error_nodev:
+       candevice_done(candev);
+       ret=-ENODEV;
+       goto error_both;
+
+    error_nomem:
+       ret=-ENOMEM;
+
+    error_both:
+       hardware_p->candevice[card]=NULL;
+       can_checked_free(candev);
+       return ret;
+       
 }
 
 /* The function init_chip_struct is used to initialize all chip_t structures
@@ -238,29 +237,26 @@ int init_chip_struct(struct candevice_t *candev)
 
        /* Alocate and initialize the chip structures */
        for (i=0; i < candev->nr_all_chips; i++) {
-               candev->chip[i]=(struct chip_t *)kmalloc(sizeof(struct chip_t),GFP_KERNEL);
+               candev->chip[i]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t));
                if (candev->chip[i]==NULL)
                        return -ENOMEM;
-               else
-                       if ( add_mem_to_list(candev->chip[i]) )
-                               return -ENOMEM;
 
                memset(candev->chip[i], 0, sizeof(struct chip_t));
                
                candev->chip[i]->write_register=candev->hwspecops->write_register;
                candev->chip[i]->read_register=candev->hwspecops->read_register;
 
-               candev->chip[i]->chipspecops=(struct chipspecops_t *)kmalloc(sizeof(struct chipspecops_t),GFP_KERNEL);
+               candev->chip[i]->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
                if (candev->chip[i]->chipspecops==NULL)
                        return -ENOMEM;
-               else
-                       if ( add_mem_to_list(candev->chip[i]->chipspecops) )
-                               return -ENOMEM;
 
-               chips_p[irq_count]=candev->chip[i];
+                chips_p[irq_count]=candev->chip[i];
                candev->chip[i]->chip_idx=i;
                candev->chip[i]->hostdevice=candev;
                candev->chip[i]->chip_irq=irq[irq_count];
+               candev->chip[i]->baudrate=baudrate[irq_count]*1000;
+               if(!candev->chip[i]->baudrate)
+                       candev->chip[i]->baudrate=baudrate[0]*1000;
                candev->chip[i]->flags=0x0;
 
                candev->hwspecops->init_chip_data(candev,i);
@@ -285,21 +281,19 @@ int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int min
 
        max_objects=hostchip->max_objects;
        for (i=0; i<max_objects; i++) {
-               obj=(struct msgobj_t *)kmalloc(sizeof(struct msgobj_t),GFP_KERNEL);
+               obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t));
                hostchip->msgobj[i]=obj;
                if (obj == NULL) 
                        return -ENOMEM;
-               else
-                       if ( add_mem_to_list(obj) )
-                               return -ENOMEM;
-
+                       
                memset(obj, 0, sizeof(struct msgobj_t));
 
                atomic_set(&obj->obj_used,0);
                INIT_LIST_HEAD(&obj->obj_users);
-               qends = (struct canque_ends_t *)kmalloc(sizeof(struct canque_ends_t), GFP_KERNEL);
+               init_timer(&obj->tx_timeout);
+               
+               qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t));
                if(qends == NULL) return -ENOMEM;
-               if(add_mem_to_list(qends)) return -ENOMEM;
                memset(qends, 0, sizeof(struct canque_ends_t));
                obj->hostchip=hostchip;
                obj->object=i+1;
index 46033f2990baaba0806d96f34e9ea9fb820b62bf..92115118be0afc465dd81c1ade039b70fd55e3b1 100644 (file)
@@ -7,12 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/sja1000.h"
 
@@ -79,9 +75,9 @@ int sja1000_chip_config(struct chip_t *chip)
        if (sja1000_standard_mask(chip,0x0000, 0xffff))
                return -ENODEV;
        
-       if (!baudrate)
-               baudrate=1000;
-       if (sja1000_baud_rate(chip,1000*baudrate,chip->clock,0,75,0))
+       if (!chip->baudrate)
+               chip->baudrate=1000000;
+       if (sja1000_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
                return -ENODEV;
 
        /* Enable hardware interrupts */
index b71b5a0acc6ce47dc596e219206619dd41c239ad..bc2fcc3efc9cd60ce5fc75ac37e947887bb5e8d7 100644 (file)
@@ -9,12 +9,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/sja1000p.h"
 
@@ -120,9 +116,9 @@ int sja1000p_chip_config(struct chip_t *chip)
        if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff))
                return -ENODEV;
        
-       if (!baudrate)
-               baudrate=1000;
-       if (sja1000p_baud_rate(chip,1000*baudrate,chip->clock,0,75,0))
+       if (!chip->baudrate)
+               chip->baudrate=1000000;
+       if (sja1000p_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
                return -ENODEV;
 
        /* Enable hardware interrupts */
index 731f6572f7a1debdcd0abc14087bf3576f6042a2..7f11d5c1b51ead9426c394d3f74baa8245d774d6 100644 (file)
@@ -7,15 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/smartcan.h"
 #include "../include/i82527.h"
index 7cb10b94f865374882b1441ac59ae4f0590e810f..793c67c7d460042f9cea112dbb07172533211255 100644 (file)
@@ -5,14 +5,8 @@
  * Version 0.6  18 Sept 2000
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/ssv.h"
 #include "../include/i82527.h"
@@ -110,7 +104,7 @@ int ssv_reset(struct candevice_t *candev)
  * RESET_ADDR represents the io-address of the hardware reset register.
  * NR_82527 represents the number of intel 82527 chips on the board.
  * NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  */
 #define RESET_ADDR 0x02
@@ -123,7 +117,7 @@ int ssv_init_hw_data(struct candevice_t *candev)
     candev->nr_82527_chips=NR_82527;
     candev->nr_sja1000_chips=0;
     candev->nr_all_chips=NR_82527;
-    candev->flags |= PROGRAMMABLE_IRQ;
+    candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
 
     return 0;
 }
@@ -177,7 +171,7 @@ int ssv_init_obj_data(struct chip_t *chip, int objnr)
 
 /* The function template_program_irq is used for hardware that uses programmable
  * interrupts. If your hardware doesn't use programmable interrupts you should
- * not set the candevices_t->flags entry to PROGRAMMABLE_IRQ and leave this
+ * not set the candevices_t->flags entry to CANDEV_PROGRAMMABLE_IRQ and leave this
  * function unedited. Again this function is hardware specific so there's no
  * example code.
  */
index 6a8275708a0334f2892fee8cf61cc841b3d58088..9b72902614bc18857fe8eb330dcddbc67566fb42 100644 (file)
  * possible to load the driver with the hardware option hw=template.
  */
 
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/template.h"
 #include "../include/i82527.h"
@@ -103,7 +98,7 @@ int template_reset(struct candevice_t *candev)
  * %RESET_ADDR represents the io-address of the hardware reset register.
  * %NR_82527 represents the number of Intel 82527 chips on the board.
  * %NR_SJA1000 represents the number of Philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
  * the hardware uses programmable interrupts.
  * Return Value: The function always returns zero
  * File: src/template.c
@@ -114,7 +109,7 @@ int template_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=NR_82527;
        candev->nr_sja1000_chips=NR_SJA1000;
        candev->nr_all_chips=NR_82527+NR_SJA1000;
-       candev->flags |= PROGRAMMABLE_IRQ;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
 
        return 0;
 }
@@ -198,7 +193,7 @@ int template_init_obj_data(struct chip_t *chip, int objnr)
  *
  * The function template_program_irq() is used for hardware that uses 
  * programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
  * leave this function unedited. Again this function is hardware specific so 
  * there's no example code.
  * Return value: The function returns zero on success or %-ENODEV on failure
index 42c0f57c6c0ab551c7a60f9d57f64d9ba24ac822..d51a5cbe2ee546b4b7e01431f9de9275ba366c4e 100644 (file)
@@ -6,12 +6,22 @@
  * Version lincan-0.2  9 Jul 2003
  */ 
 
-#include <linux/autoconf.h>
-
-#include <linux/delay.h>
-#include <asm/errno.h>
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 
+
+long virtual_bus_latency(struct msgobj_t *obj)
+{
+       long latency;
+       latency=obj->hostchip->baudrate;
+       if(latency){
+               latency=(long)HZ*1000/latency;
+       }
+       return latency;
+}
+
+
 /* * * Virtual Chip Functionality * * */
 
 int virtual_enable_configuration(struct chip_t *chip)
@@ -275,6 +285,58 @@ irqreturn_t virtual_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+
+void virtual_schedule_next(struct msgobj_t *obj)
+{
+       int cmd;
+        /* dummy lock to prevent preemption fully portable way */
+       spinlock_t dummy_lock;
+
+       /*  preempt_disable() */
+       spin_lock_init(&dummy_lock);
+       spin_lock(&dummy_lock);
+
+       set_bit(OBJ_TX_REQUEST,&obj->flags);
+       
+       while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
+
+               clear_bit(OBJ_TX_REQUEST,&obj->flags);
+               
+               cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+               if(cmd>=0) {
+                       mod_timer(&obj->tx_timeout,
+                               jiffies+virtual_bus_latency(obj));
+                       CANMSG("virtual: scheduled delivery\n");
+
+               } else          
+                       clear_bit(OBJ_TX_LOCK,&obj->flags);
+               
+               if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+               DEBUGMSG("TX looping in virtual_schedule_next\n");
+       }
+
+       /* preempt_enable(); */
+       spin_unlock(&dummy_lock);
+}
+
+
+void virtual_do_tx_timeout(unsigned long data)
+{
+       struct msgobj_t *obj=(struct msgobj_t *)data;
+       
+       if(obj->tx_slot) {
+               /* Deliver message to edges */
+               canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               /* Free transmitted slot */
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+               CANMSG("virtual: delayed delivery\n");
+       }
+       clear_bit(OBJ_TX_LOCK,&obj->flags);
+
+       virtual_schedule_next(obj);
+}
+
 /**
  * virtual_wakeup_tx: - wakeups TX processing
  * @chip: pointer to chip state structure
@@ -291,13 +353,17 @@ int virtual_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
        struct canque_slot_t *slot;
        int cmd;
        
-       /* Ensure delivery of all ready slots */
-       
-       while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
-               if(cmd==0) {
-                       canque_filter_msg2edges(obj->qends, &slot->msg);
+       if(!virtual_bus_latency(obj)) {
+               /* Ensure delivery of all ready slots */
+               while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
+                       if(cmd==0) {
+                               canque_filter_msg2edges(obj->qends, &slot->msg);
+                               CANMSG("virtual: direct delivery\n");
+                       }
+                       canque_free_outslot(obj->qends, qedge, slot);
                }
-               canque_free_outslot(obj->qends, qedge, slot);
+       } else {
+               virtual_schedule_next(obj);
        }
 
        return 0;
@@ -356,7 +422,7 @@ int virtual_init_hw_data(struct candevice_t *candev)
        candev->nr_82527_chips=0;
        candev->nr_sja1000_chips=0;
        candev->nr_all_chips=1;
-       candev->flags |= PROGRAMMABLE_IRQ*0;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
 
        return 0;
 }
@@ -415,8 +481,11 @@ int virtual_init_chip_data(struct candevice_t *candev, int chipnr)
  */
 int virtual_init_obj_data(struct chip_t *chip, int objnr)
 {
-       chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
-       chip->msgobj[objnr]->flags=0;
+       struct msgobj_t *obj=chip->msgobj[objnr];
+       obj->obj_base_addr=chip->chip_base_addr;
+       obj->flags=0;
+       obj->tx_timeout.function=virtual_do_tx_timeout;
+       obj->tx_timeout.data=(unsigned long)obj;
        return 0;
 }
 
index 2f32b2ead2fb30ba9e7fdb6530ff92f3f47763c4..1869c9750940d8ad13b329315bf444d819e5c80c 100644 (file)
@@ -7,16 +7,8 @@
  * Version lincan-0.2  9 Jul 2003
  */
 
-#include <linux/autoconf.h>
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
 #include "../include/main.h"
 
 ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
@@ -70,11 +62,12 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
        if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
                        0, msg_buff.id, 0))<0){
                DEBUGMSG("Buffer is full\n");
-               if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
                if(ret < -1)
                        return -EIO;
 
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
                ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot, 
                                                0, msg_buff.id, 0);
                if(ret<0) {
index 0fbdc44a06c55f5d807d81d6abde16a380839858..a05c3428eb12c4eebb65f3914e8311d5fe88d491 100644 (file)
@@ -13,7 +13,7 @@ ifndef CC
 CC = gcc
 endif
 
-CFLAGS = -I../include -O2
+CFLAGS = -I../include -O2 -Wall
 
 all: default
 
index 0e32b63d083761056ff45882b34276372f9ccbd4..4d715d12ca373414bd874fd7954b0aedc120776e 100644 (file)
 
 int canmsg_flags = 0;
 unsigned long canmsg_id = 5;
+int block = 10;
+int count = 0;
 
 int can_wait_sec = 1;
+int o_sync_fl = 0;
 
 char *can_dev_name = "/dev/can0";
 
@@ -28,7 +31,10 @@ usage(void)
   printf("  -d, --device  <name>     name of CAN device [/dev/can0]\n");
   printf("  -i, --id  <num>          ID of generated messages\n");
   printf("  -f, --flags <num>        CAN filter flags\n");
+  printf("  -s, --sync               open in synchronous mode\n");
   printf("  -w, --wait <num>         number of seconds to wait between messages\n");
+  printf("  -b, --block <num>        number of messages in  block\n");
+  printf("  -c, --count <num>        number of sent blocks of messages\n");
   printf("  -p, --prefix <str>       string prefix for output\n");
   printf("  -V, --version            show version\n");
   printf("  -h, --help               this usage screen\n");
@@ -40,7 +46,10 @@ int main(int argc, char *argv[])
                { "uldev", 1, 0, 'd' },
                { "id",    1, 0, 'i' },
                { "flags", 1, 0, 'f' },
+               { "sync",  0, 0, 's' },
                { "wait",  1, 0, 'w' },
+               { "block", 1, 0, 'b' },
+               { "count", 1, 0, 'c' },
                { "prefix",1, 0, 'p' },
                { "version",0,0, 'V' },
                { "help",  0, 0, 'h' },
@@ -51,7 +60,7 @@ int main(int argc, char *argv[])
        struct canmsg_t sendmsg={0,0,5,0,8,{1,2,3,4,5,6,7,8}};
        int fd, ret,i,j;
 
-       while ((opt = getopt_long(argc, argv, "d:i:f:w:p:Vh",
+       while ((opt = getopt_long(argc, argv, "d:i:f:sw:b:c:p:Vh",
                            &long_opts[0], NULL)) != EOF) switch (opt) {
                case 'd':
                        can_dev_name=optarg;
@@ -62,9 +71,18 @@ int main(int argc, char *argv[])
                case 'f':
                        canmsg_flags = strtol(optarg,NULL,0);
                        break;
+               case 's':
+                       o_sync_fl = 1;
+                       break;
                case 'w':
                        can_wait_sec = strtol(optarg,NULL,0);
                        break;
+               case 'b':
+                       block = strtol(optarg,NULL,0);
+                       break;
+               case 'c':
+                       count = strtol(optarg,NULL,0);
+                       break;
                case 'p':
                        prt_prefix_in = optarg;
                        break;
@@ -77,7 +95,7 @@ int main(int argc, char *argv[])
                        exit(opt == 'h' ? 0 : 1);
        }
 
-       if ((fd=open(can_dev_name, O_RDWR)) < 0) {
+       if ((fd=open(can_dev_name, O_RDWR | (o_sync_fl? O_SYNC:0))) < 0) {
                perror("open");
                printf("Error opening %s\n", can_dev_name);
                exit(1);        
@@ -87,7 +105,7 @@ int main(int argc, char *argv[])
 
        j=0;
        while (1) {
-               for(i=0;i<10;i++) {
+               for(i=0;i<block;i++) {
                        sendmsg.flags=canmsg_flags;
                        sendmsg.id=canmsg_id;
                        sendmsg.data[0]=i;
@@ -98,9 +116,11 @@ int main(int argc, char *argv[])
                                break;
                        }
                }
-               printf("%sSent block of 10 messages #: %u\n", prt_prefix, j);
+               printf("%sSent block of %d messages #: %u\n", prt_prefix, block, j);
                j++;
                usleep(1000000*can_wait_sec);
+               if(count)
+                       if(!--count) break;
        }
        close(fd);
        return 0;