]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Added full RT-Linux POSIX interface to LinCAN driver, needs preparation of RT tests.
authorppisa <ppisa>
Sun, 4 Jan 2004 00:09:32 +0000 (00:09 +0000)
committerppisa <ppisa>
Sun, 4 Jan 2004 00:09:32 +0000 (00:09 +0000)
Linux-only and RT-Linux chip thread based version passed Linux users-pace
tests on PCM3680 and PiKRON ISA cards.
Fundamental design flaws found in rtl_posixio.c concerning concurrent open
and/or close processing. There is even bug if open fails reaction.
The fiels private_data should be added to structure rtl_file.

19 files changed:
lincan/include/can_iortl.h [new file with mode: 0644]
lincan/include/can_queue.h
lincan/include/can_sysdep.h
lincan/include/constants.h
lincan/include/main.h
lincan/src/Makefile.omk
lincan/src/can_quekern.c
lincan/src/can_quertl.c
lincan/src/close.c
lincan/src/close_rtl.c [new file with mode: 0644]
lincan/src/ioctl.c
lincan/src/ioctl_rtl.c [new file with mode: 0644]
lincan/src/main.c
lincan/src/open.c
lincan/src/open_rtl.c [new file with mode: 0644]
lincan/src/read.c
lincan/src/read_rtl.c [new file with mode: 0644]
lincan/src/write.c
lincan/src/write_rtl.c [new file with mode: 0644]

diff --git a/lincan/include/can_iortl.h b/lincan/include/can_iortl.h
new file mode 100644 (file)
index 0000000..735bfae
--- /dev/null
@@ -0,0 +1,28 @@
+/* can_iortl.h - RT-Linux Posix file IO interface
+ * Linux CAN-bus device driver.
+ * RT-Linux support 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
+ */
+
+#ifndef _CAN_IORTL_H
+#define _CAN_IORTL_H
+
+#ifdef CAN_WITH_RTL
+
+int can_open_rtl_posix(struct rtl_file *fptr);
+
+int can_release_rtl_posix(struct rtl_file *fptr);
+
+ssize_t can_read_rtl_posix(struct rtl_file *fptr, char *buffer,
+                               size_t length, loff_t *ppos);
+
+ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer,
+                                size_t length, loff_t *ppos);
+
+int can_ioctl_rtl_posix(struct rtl_file *, unsigned int, unsigned long);
+
+#endif /*CAN_WITH_RTL*/
+
+#endif /*_CAN_IORTL_H*/
index aacfd846f2b52ebfada182ef72a91897a8810d5b..b8cbb0989b7286a1006aa62e57c930e5ca48e8aa 100644 (file)
@@ -362,8 +362,11 @@ struct canque_ends_t {
                struct {
                        rtl_spinlock_t rtl_lock;
                        rtl_wait_t rtl_readq;
+                       atomic_t   rtl_readq_age;
                        rtl_wait_t rtl_writeq;
+                       atomic_t   rtl_writeq_age;
                        rtl_wait_t rtl_emptyq;
+                       atomic_t   rtl_emptyq_age;
                        unsigned long pend_flags;
                } rtlinfo;
            #endif /*CAN_WITH_RTL*/
@@ -687,7 +690,16 @@ void canqueue_ends_dispose_postpone(struct canque_ends_t *qends);
 void canqueue_kern_initialize(void);
 
 #ifdef CAN_WITH_RTL
-/* RT-Linux specific functions */
+
+extern struct tasklet_struct canque_dead_tl;   /*publication required only for RTL*/
+
+/* RT-Linux specific functions and variables */
+
+extern int canqueue_rtl_irq;
+
+extern unsigned long canqueue_rtl2lin_pend;
+
+#define CAN_RTL2LIN_PEND_DEAD_b 0
 
 void canqueue_rtl_initialize(void);
 void canqueue_rtl_done(void);
@@ -699,8 +711,19 @@ struct canque_edge_t *canque_new_edge_rtl(int slotsnr);
 
 void canque_dispose_edge_rtl(struct canque_edge_t *qedge);
 
+int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio);
+
+int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp);
+
+int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge);
+
 void canque_ends_free_rtl(struct canque_ends_t *qends);
 
+int canqueue_ends_init_rtl(struct canque_ends_t *qends);
+
 int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync);
 
 #else /*CAN_WITH_RTL*/
index 1de145449c9fd3237eabe20185a4d46bc302dbac..56cfc4ed2ffcfbf20cfda693b460770ccbbd18a0 100644 (file)
 #else /*CAN_WITH_RTL*/
 
 #define can_spinlock_t             rtl_spinlock_t
-#define can_spin_irqflags_t        unsigned long
+#define can_spin_irqflags_t        rtl_irqstate_t
 #define can_spin_lock              rtl_spin_lock
 #define can_spin_unlock            rtl_spin_unlock
 #define can_spin_lock_irqsave      rtl_spin_lock_irqsave
 
 #define can_printk                 rtl_printf
 
+/*
+ * terrible hack to test rtl_file private_data concept, ugh !!!
+ * this would result in crash on architectures,  where 
+ * sizeof(int) < sizeof(void *)
+ */
+#define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0)
+#define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor))
+
 #endif /*CAN_WITH_RTL*/
 
 #endif /*_CAN_SYSDEP_H*/
index ce0cbbd96ccf85fedbbb7ae1a0eb5103ee1e9457..df2909f8676e2542f694dad77a9a4206857605fa 100644 (file)
 #define CANDEV_PROGRAMMABLE_IRQ (1<<0)
 #define CANDEV_IO_RESERVED     (1<<1)
 
+/* Next flags are specific for struct canuser_t applications connection */
+#define CANUSER_RTL_CLIENT      (1<<0)
+#define CANUSER_RTL_MEM         (1<<1)
+#define CANUSER_DIRECT          (1<<2)
+
+
 enum timing_BTR1 {
        MAX_TSEG1 = 15,
        MAX_TSEG2 = 7
index 4d42d4df0624417dff0d5bb8d9f9292ffe044882..ba01dd23d89b54b767b2c5e257a24a9a4eaeed5e 100644 (file)
@@ -22,6 +22,8 @@
 #define CANMSG(fmt,args...) can_printk(KERN_ERR "can.o: " fmt,##args)
 
 
+extern can_spinlock_t canuser_manipulation_lock;
+
 /**
  * struct canhardware_t - structure representing pointers to all CAN boards
  * @nr_boards: number of present boards
@@ -153,9 +155,10 @@ struct chip_t {
        
        int max_objects;        /* 1 for sja1000, 15 for i82527 */
 
+       can_spinlock_t chip_lock;
+
     #ifdef CAN_WITH_RTL
        pthread_t worker_thread;
-       rtl_spinlock_t rtl_lock;
        unsigned long pend_flags;
     #endif /*CAN_WITH_RTL*/
 };
@@ -207,20 +210,33 @@ struct msgobj_t {
 
 /**
  * struct canuser_t - structure holding CAN user/client state
+ * @flags: used to distinguish Linux/RT-Linux type
  * @peers: for connection into list of object users
  * @qends: pointer to the ends structure corresponding for this user
- * @file: pointer to open device file state structure
  * @msgobj: communication object the user is connected to
  * @rx_edge0: default receive queue for filter IOCTL
+ * @userinfo: stores user context specific information.
+ *     The field @fileinfo.file holds pointer to open device file state structure
+ *     for the Linux user-space client applications
  * @magic: magic number to check consistency when pointer is retrieved
  *     from file private field
  */
 struct canuser_t {
+       unsigned long flags;
        struct list_head peers;
        struct canque_ends_t *qends;
-        struct file *file;      /* back ptr to file */
        struct msgobj_t *msgobj;
        struct canque_edge_t *rx_edge0; /* simplifies IOCTL */
+        union {
+               struct {
+                       struct file *file;  /* back ptr to file */
+               } fileinfo;
+           #ifdef CAN_WITH_RTL
+               struct {
+                       struct rtl_file *file;
+               } rtlinfo;
+           #endif /*CAN_WITH_RTL*/
+       } userinfo;
        int magic;
 };
 
index bbdcba749462fb4a6a9a3aeb360234ee2c04e8e8..37efccab36694275840cb6da53fa37a71118fc29 100644 (file)
@@ -10,10 +10,12 @@ kernel_MODULES = lincan
 lincan_cards_SOURCES = pip.c pccan.c smartcan.c nsi.c cc_can104.c \
                pc_i03.c pcm3680.c aim104.c m437.c pcccan.c ssv.c \
                bfadcan.c pikronisa.c virtual.c template.c
+               
+lincan_rtl_SOURCES = open_rtl.c close_rtl.c read_rtl.c write_rtl.c ioctl_rtl.c
 
 lincan_SOURCES = can_queue.c can_quekern.c can_quertl.c main.c modparms.c \
                devcommon.c can_devrtl.c setup.c finish.c irq.c boardlist.c \
                sja1000p.c sja1000.c i82527.c  \
-               open.c proc.c close.c write.c read.c \
-               ioctl.c select.c fasync.c proc.c $(lincan_cards_SOURCES)
+               open.c close.c read.c write.c ioctl.c select.c fasync.c \
+               proc.c $(lincan_cards_SOURCES) $(lincan_rtl_SOURCES)
                
index 39c033070fa5b042f03d967af53c2db4d944554f..093886c2c41e01e9dfb0cdd5727a8aba993e626d 100644 (file)
@@ -84,8 +84,10 @@ void canque_dead_func(unsigned long data)
        can_spin_lock_irqsave(&canque_dead_func_lock, flags);
        entry=canque_dead_ends.next;
        can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+       /* lock can be released there, because only one instance of canque_dead_tl
+          can run at once and all other functions add ends only to head */
        while(entry!=&canque_dead_ends){
-               qends=list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers);
+               qends=list_entry(entry,struct canque_ends_t,dead_peers);
                entry=entry->next;
                if(!list_empty(&qends->inlist))
                        continue;
@@ -106,6 +108,19 @@ void canque_dead_func(unsigned long data)
 
 }
 
+static inline void canque_dead_tasklet_schedule(void)
+{
+    #ifdef CAN_WITH_RTL
+       if(!rtl_rt_system_is_idle()){
+               set_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend);
+               rtl_global_pend_irq (canqueue_rtl_irq);
+               return;
+       }
+    #endif /*CAN_WITH_RTL*/
+
+       tasklet_schedule(&canque_dead_tl);
+}
+
 
 void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
 {
@@ -121,7 +136,7 @@ void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
        can_spin_lock_irqsave(&canque_dead_func_lock, flags);
        list_add(&edge->inpeers,&canque_dead_edges);
        can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
-       tasklet_schedule(&canque_dead_tl);
+       canque_dead_tasklet_schedule();
 }
 
 
@@ -427,7 +442,7 @@ void canqueue_ends_dispose_postpone(struct canque_ends_t *qends)
        qends->ends_flags |= CAN_ENDSF_DEAD;
        list_add(&qends->dead_peers,&canque_dead_ends);
        can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
-       tasklet_schedule(&canque_dead_tl);
+       canque_dead_tasklet_schedule();
 }
 
 
index 45129b41b480418d395e0dfb754a8893ddae69bc..0a6fa40d38c90e4a5520161cb84d2542eeb08af5 100644 (file)
@@ -28,8 +28,9 @@ extern int processlocal;
 
 struct list_head canque_pending_edges_list;
 can_spinlock_t canque_pending_edges_lock;
+unsigned long canqueue_rtl2lin_pend;
 
-static int canqueue_rtl_irq = 0;
+int canqueue_rtl_irq = 0;
 
 void
 canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
@@ -75,6 +76,9 @@ canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
 
        can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
 
+       if(test_and_clear_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend))
+               tasklet_schedule(&canque_dead_tl);
+
        return;
 }
 
@@ -119,6 +123,111 @@ int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
 }
 
 
+/**
+ * canque_get_inslot4id_wait_rtl - 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_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio)
+{
+       rtl_irqstate_t flags;
+       int ret;
+       unsigned old_age;
+       rtl_sigset_t sigset;
+       
+       old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
+       while((ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))==-1){
+               rtl_sigemptyset(&sigset);
+               rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age))
+                       sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_writeq, &qends->endinfo.rtlinfo.rtl_lock);
+               rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(RTL_SIGINTR(&sigset))
+                       return -1;
+               old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
+       }
+       
+       return ret;
+}
+
+
+/**
+ * canque_get_outslot_wait_rtl - 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_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+{
+       rtl_irqstate_t flags;
+       int ret;
+       unsigned old_age;
+       rtl_sigset_t sigset;
+       
+       old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
+       while((ret=canque_test_outslot(qends,qedgep,slotp))==-1){
+               rtl_sigemptyset(&sigset);
+               rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age))
+                       sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_readq, &qends->endinfo.rtlinfo.rtl_lock);
+               rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(RTL_SIGINTR(&sigset))
+                       return -1;
+               old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
+       }
+       return ret;
+}
+
+
+/**
+ * canque_sync_wait_rtl - 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_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+       rtl_irqstate_t flags;
+       int ret;
+       unsigned old_age;
+       rtl_sigset_t sigset;
+       
+       old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
+       while(!(ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)){
+               rtl_sigemptyset(&sigset);
+               rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age))
+                       sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_emptyq, &qends->endinfo.rtlinfo.rtl_lock);
+               rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+               if(RTL_SIGINTR(&sigset))
+                       return -1;
+               old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
+       }
+       
+       return ret;
+}
+
+
 /**
  * canque_fifo_init_rtl - initialize one CAN FIFO
  * @fifo: pointer to the FIFO structure
@@ -138,6 +247,7 @@ int canque_fifo_init_rtl(struct canque_fifo_t *fifo, int slotsnr)
        return canque_fifo_init_slots(fifo);
 }
 
+
 /**
  * canque_fifo_done_rtl - frees slots allocated for CAN FIFO
  * @fifo: pointer to the FIFO structure
@@ -207,6 +317,7 @@ void canqueue_notify_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedg
        switch(what){
                case CANQUEUE_NOTIFY_EMPTY:
                        rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
                        rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
                        if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
@@ -214,19 +325,28 @@ void canqueue_notify_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedg
                        break;
                case CANQUEUE_NOTIFY_SPACE:
                        rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
                        rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
                        break;
                case CANQUEUE_NOTIFY_PROC:
                        rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
                        rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
                        break;
                case CANQUEUE_NOTIFY_NOUSR:
                        rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
+
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
+
+                       atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
                        rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
+
                        rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
                        break;
                case CANQUEUE_NOTIFY_DEAD_WANTED:
index 73d4764d6662664bd06eec67255035b24875c0ea..9042ff2a2ec0d4e188dd2a12cad32315e8c458cf 100644 (file)
@@ -23,6 +23,7 @@ int can_close(struct inode *inode, struct file *file)
        struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
        struct canque_ends_t *qends;
        struct msgobj_t *obj;
+       can_spin_irqflags_t iflags;
        
        if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
                CANMSG("can_close: bad canuser magic\n");
@@ -31,23 +32,26 @@ int can_close(struct inode *inode, struct file *file)
        
        obj = canuser->msgobj;
        qends = canuser->qends;
-
+       
     #ifdef CAN_ENABLE_KERN_FASYNC
 
        can_fasync(-1, file, 0);
 
     #endif /*CAN_ENABLE_KERN_FASYNC*/
 
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
        list_del(&canuser->peers);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
        canuser->qends = NULL;
        canqueue_ends_dispose_kern(qends, file->f_flags & O_SYNC);
 
        kfree(canuser);
 
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
        if(atomic_dec_and_test(&obj->obj_used)){
                can_msgobj_clear_fl(obj,OPENED);
-               /* FIXME: what about clearing chip HW status, stopping sending messages etc? */
        };
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
        
     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
        MOD_DEC_USE_COUNT;
diff --git a/lincan/src/close_rtl.c b/lincan/src/close_rtl.c
new file mode 100644 (file)
index 0000000..5f8188b
--- /dev/null
@@ -0,0 +1,72 @@
+/* close.c
+ * Linux CAN-bus device 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_malloc.h>
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+static inline
+int can_release_rtl_common(struct canuser_t *canuser, int file_flags)
+{
+       struct canque_ends_t *qends;
+       struct msgobj_t *obj;
+       can_spin_irqflags_t iflags;
+
+       obj = canuser->msgobj;
+       qends = canuser->qends;
+
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+       list_del(&canuser->peers);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+       canuser->qends = NULL;
+       canqueue_ends_dispose_rtl(qends, file_flags & O_SYNC);
+
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+       if(atomic_dec_and_test(&obj->obj_used)){
+               can_msgobj_clear_fl(obj,OPENED);
+       };
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+    #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
+       MOD_DEC_USE_COUNT;
+    #endif
+
+       return 0;
+}
+
+
+int can_release_rtl_posix(struct rtl_file *fptr)
+{
+       struct canuser_t *canuser =
+               (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+       int ret;
+       
+       if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+               CANMSG("can_release_rtl_posix: bad canuser magic\n");
+               return -ENODEV;
+       }
+
+       ret=can_release_rtl_common(canuser, fptr->f_flags);
+
+       rt_free(canuser);
+       
+       return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
+
index 38743fabbac9bd5805db4b8fd38d9b85b70a0302..51feb5b0fc5cd42e2652dea00c737b66e47b37c4 100644 (file)
@@ -24,7 +24,7 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
        struct canque_ends_t *qends;
        
        if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
-               CANMSG("can_close: bad canuser magic\n");
+               CANMSG("can_ioctl: bad canuser magic\n");
                return -ENODEV;
        }
        
diff --git a/lincan/src/ioctl_rtl.c b/lincan/src/ioctl_rtl.c
new file mode 100644 (file)
index 0000000..449b345
--- /dev/null
@@ -0,0 +1,108 @@
+/* ioctl.c
+ * Linux CAN-bus device 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+
+int can_ioctl_rtl_posix(struct rtl_file *fptr, unsigned int cmd, unsigned long arg)
+{
+       struct canuser_t *canuser =
+               (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+       int i=0;
+       unsigned short channel=0;
+       unsigned btr0=0, btr1=0;
+       struct msgobj_t *obj;
+       struct chip_t *chip;
+       struct canque_ends_t *qends;
+       
+       if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+               CANMSG("can_ioctl_: bad canuser magic\n");
+               return -ENODEV;
+       }
+       
+       obj = canuser->msgobj;
+       if (obj == NULL) {
+               CANMSG("Could not assign buffer structure\n");
+               return -1;
+       }
+
+       qends = canuser->qends;
+       chip = obj->hostchip;
+       if (chip == NULL) {
+               CANMSG("Device is not correctly configured.\n");
+               CANMSG("Please reload the driver.\n");
+               return -1;
+       }
+
+       switch (cmd) {
+               case STAT: {
+                       for (i=0x0; i<0x100; i++)
+                               CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i));
+                       break;
+               }
+               case CMD_START: {
+                       if (chip->chipspecops->start_chip(chip))
+                               return -1;
+                       break;
+               }
+               case CMD_STOP: {
+                       if (chip->chipspecops->stop_chip(chip))
+                               return -1;
+                       break;
+               }
+               case CANQUE_FLUSH: {
+                       canque_flush(canuser->rx_edge0);
+                       break;
+               }
+               case CONF_FILTER: {
+                       if(canuser->rx_edge0){
+                               canque_set_filt(canuser->rx_edge0, arg, ~0, 0);
+                       }
+
+                       break;
+               }
+               
+               case CANQUE_FILTER: {
+                       struct canfilt_t canfilt;
+                       copy_from_user(&canfilt, (void*)arg, sizeof(struct canfilt_t));
+                       if(canuser->rx_edge0){
+                               canque_set_filt(canuser->rx_edge0, canfilt.id, canfilt.mask, canfilt.flags);
+                       }
+                       break;
+               }
+
+               case CONF_BAUD: {
+                       channel = arg & 0xff;
+                       btr0 = (arg >> 8) & 0xff;
+                       btr1 = (arg >> 16) & 0xff;
+
+                       if (chip->chipspecops->set_btregs(chip, btr0, btr1)) {
+                               CANMSG("Error setting bit timing registers\n");
+                               return -1;
+                       }
+                       break;
+               }
+               default: {
+                       CANMSG("Not a valid ioctl command\n");
+                       return -EINVAL;
+               }
+               
+       }
+
+       return 0;
+}
+
+#endif /*CAN_WITH_RTL*/
index c40310dbde3cc2738d6189ce1488e27246056ec5..38a0ec0d56b78f6f47b302e075bc3ead14c7e2e8 100644 (file)
 #include "../include/finish.h"
 #include "../include/fasync.h"
 
+#ifdef CAN_WITH_RTL
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+#endif /*CAN_WITH_RTL*/
+
 #define EXPORT_SYMTAB
 
+can_spinlock_t canuser_manipulation_lock;
+
 /* Module parameters, some must be supplied at module loading time */
 int major=CAN_MAJOR;
 MODULE_PARM(major,"1i");
@@ -130,6 +137,20 @@ struct file_operations can_fops=
 
 EXPORT_SYMBOL(can_fops);
 
+
+#ifdef CAN_WITH_RTL
+struct rtl_file_operations can_fops_rtl = {
+       llseek:         NULL,
+       read:           can_read_rtl_posix,
+       write:          can_write_rtl_posix,
+       ioctl:          can_ioctl_rtl_posix,
+       mmap:           NULL,
+       open:           can_open_rtl_posix,
+       release:        can_release_rtl_posix
+};
+#endif /*CAN_WITH_RTL*/
+
+
 int init_module(void)
 {
        int res=0,i=0, j;
@@ -156,6 +177,11 @@ int init_module(void)
 
        #ifdef CAN_WITH_RTL
        canqueue_rtl_initialize();
+       res=rtl_register_rtldev(major,DEVICE_NAME,&can_fops_rtl);
+       if (res<0) {
+               CANMSG("Error registering RT-Linux major number.\n");
+               goto rtldev_error;
+       }
        #endif /*CAN_WITH_RTL*/
 
        for (i=0; i<hardware_p->nr_boards; i++) {
@@ -233,6 +259,8 @@ int init_module(void)
                canhardware_done(hardware_p);
 
                #ifdef CAN_WITH_RTL
+               rtl_unregister_rtldev(major,DEVICE_NAME);
+       rtldev_error:
                canqueue_rtl_done();
                #endif /*CAN_WITH_RTL*/
 
@@ -272,6 +300,7 @@ void cleanup_module(void)
        canhardware_done(hardware_p);
 
        #ifdef CAN_WITH_RTL
+       rtl_unregister_rtldev(major,DEVICE_NAME);
        canqueue_rtl_done();
        #endif /*CAN_WITH_RTL*/
 
index 015b52107130b5c691f5a874d3be3720dc79ebd3..deb027ca8e8a430ffeb205e89e0721ca0bd921b0 100644 (file)
@@ -24,6 +24,7 @@ int can_open(struct inode *inode, struct file *file)
        struct canuser_t *canuser;
        struct canque_ends_t *qends;
        struct canque_edge_t *edge;
+       can_spin_irqflags_t iflags;
 
        if ( ((obj=objects_p[MINOR_NR]) == NULL) || 
                        ((chip=objects_p[MINOR_NR]->hostchip) == NULL) ) {
@@ -50,7 +51,8 @@ int can_open(struct inode *inode, struct file *file)
 
        canuser = (struct canuser_t *)kmalloc(sizeof(struct canuser_t), GFP_KERNEL);
        if(canuser == NULL) goto no_canuser;
-       canuser->file = file;
+       canuser->flags=0;
+       canuser->userinfo.fileinfo.file = file;
        canuser->msgobj = obj;
        canuser->magic = CAN_USER_MAGIC;
        file->private_data = canuser;
@@ -60,7 +62,10 @@ int can_open(struct inode *inode, struct file *file)
        canqueue_ends_init_kern(qends);
        canuser->qends = qends;
        
+       /*required to synchronize with RT-Linux context*/
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
        list_add(&canuser->peers, &obj->obj_users);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
 
        if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
                canuser->qends, obj->qends)<0) goto no_tx_qedge;
diff --git a/lincan/src/open_rtl.c b/lincan/src/open_rtl.c
new file mode 100644 (file)
index 0000000..230e3eb
--- /dev/null
@@ -0,0 +1,136 @@
+/* open.c
+ * Linux CAN-bus device 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_malloc.h>
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+
+static inline
+int can_open_rtl_common(struct canuser_t *canuser, int open_flags)
+{
+       struct msgobj_t *obj=canuser->msgobj;
+       struct chip_t *chip;
+       struct canque_ends_t *qends;
+       struct canque_edge_t *edge;
+       can_spin_irqflags_t iflags;
+
+       if(!obj) return -ENODEV;
+       
+       can_msgobj_set_fl(obj,OPENED);
+       
+       chip=obj->hostchip;
+       if (chip) {
+               if (!(chip->flags & CHIP_CONFIGURED)) {
+                       if (chip->chipspecops->chip_config(chip))
+                               CANMSG("Error configuring chip.\n");
+                       else
+                               chip->flags |= CHIP_CONFIGURED; 
+
+                       if (chip->chipspecops->pre_read_config(chip,obj)<0)
+                               CANMSG("Error initializing chip for receiving\n");
+
+               }
+       } /* End of chip configuration */
+
+
+       qends = (struct canque_ends_t *)rt_malloc(sizeof(struct canque_ends_t));
+       if(qends == NULL) goto no_qends;
+       canqueue_ends_init_rtl(qends);
+       canuser->qends = qends;
+       
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+       list_add(&canuser->peers, &obj->obj_users);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+       if(canqueue_connect_edge(edge=canque_new_edge_rtl(MAX_BUF_LENGTH),
+               canuser->qends, obj->qends)<0) goto no_tx_qedge;
+
+       if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_rtl(MAX_BUF_LENGTH),
+               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;      /*is this enough for RT-Linux context ?*/
+#endif 
+
+       return 0;
+       
+    no_rx_qedge:
+       canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+       canque_edge_decref(edge);
+    no_tx_qedge:
+       list_del(&canuser->peers);
+       canuser->qends = NULL;
+       canqueue_ends_dispose_kern(qends, 1);
+
+    no_qends:
+
+       return -ENOMEM;
+}
+
+
+int can_open_rtl_posix(struct rtl_file *fptr)
+{
+       int ret;
+       struct msgobj_t *obj;
+       struct chip_t *chip;
+       struct canuser_t *canuser;
+       int minor_nr = RTL_MINOR_FROM_FILEPTR(fptr);
+       
+       if(minor_nr>=MAX_TOT_MSGOBJS)
+               return -ENODEV;
+
+       if ( ((obj=objects_p[minor_nr]) == NULL) || 
+                       ((chip=objects_p[minor_nr]->hostchip) == NULL) ) {
+               CANMSG("There is no hardware support for the device file with minor nr.: %d\n",minor_nr);
+               return -ENODEV;
+       }
+
+       atomic_inc(&obj->obj_used);
+       DEBUGMSG("Device %d opened %d times.\n", minor_nr, atomic_read(&obj->obj_used));
+
+       canuser = (struct canuser_t *)rt_malloc(sizeof(struct canuser_t));
+       if(canuser == NULL){
+               ret=-ENOMEM;
+               goto no_canuser;
+       }
+       canuser->flags=CANUSER_RTL_CLIENT | CANUSER_RTL_MEM;
+       canuser->userinfo.rtlinfo.file = fptr;
+       canuser->msgobj = obj;
+       canuser->magic = CAN_USER_MAGIC;
+
+       /*next line would solve many problems, but RT-Linux lacks this fundamental field */
+       /*fptr->private_data = canuser;*/
+       /*to test code I am adding this terible hack*/
+       can_set_rtl_file_private_data(fptr,canuser);
+
+       ret=can_open_rtl_common(canuser, fptr->f_flags);
+       if(ret>=0) return ret;
+
+       rt_free(canuser);
+
+    no_canuser:
+       atomic_dec(&obj->obj_used);
+       
+       return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
index d203f0f0885bd9c7e58636b05c296525aaed2872..88248901b968882045a9a7e40a0b9ce7b08b0b69 100644 (file)
@@ -130,7 +130,7 @@ ssize_t can_read(struct file *file, char *buffer, size_t length, loff_t *offset)
        int ret=0;
 
        if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
-               CANMSG("can_close: bad canuser magic\n");
+               CANMSG("can_read: bad canuser magic\n");
                return -ENODEV;
        }
 
diff --git a/lincan/src/read_rtl.c b/lincan/src/read_rtl.c
new file mode 100644 (file)
index 0000000..807f572
--- /dev/null
@@ -0,0 +1,93 @@
+/* read.c
+ * Linux CAN-bus device 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+/* This is the 'Normal' read handler for normal transmission messages */
+static inline 
+ssize_t can_std_read_rtl(struct canque_ends_t *qends, int nonblock_fl, 
+                       char *buffer, size_t length)
+{
+       int ret;
+       struct canmsg_t *msg_buff = (struct canmsg_t *)buffer;
+       int bytes_to_copy;
+       struct canque_edge_t *qedge;
+       struct canque_slot_t *slot;
+       
+       ret=canque_test_outslot(qends, &qedge, &slot);
+       if(ret<0){
+               if (nonblock_fl) {
+                       return -EAGAIN;
+               }
+               ret=canque_get_outslot_wait_rtl(qends, &qedge, &slot);
+               if(ret<0){
+                       if (ret==-1) {
+                               DEBUGMSG("Rx interrupted\n");
+                               return -EINTR;
+                       }
+
+                       return -EIO;
+               }
+       }
+       *(msg_buff++)=slot->msg;
+       canque_free_outslot(qends, qedge, slot);
+       bytes_to_copy = length-sizeof(struct canmsg_t);
+       
+       while (bytes_to_copy > 0) {
+               ret=canque_test_outslot(qends, &qedge, &slot);
+               if(ret<0)
+                       break;
+               *(msg_buff++)=slot->msg;
+               canque_free_outslot(qends, qedge, slot);
+               bytes_to_copy -= sizeof(struct canmsg_t);
+       }
+
+       return length-bytes_to_copy;
+}
+
+
+ssize_t can_read_rtl_posix(struct rtl_file *fptr, char *buffer,
+                               size_t length, loff_t *ppos)
+{
+       struct canuser_t *canuser = 
+               (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+       struct canque_ends_t *qends;
+       int      ret;
+
+       if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+               CANMSG("can_read_rtl_posix: bad canuser magic\n");
+               return -ENODEV;
+       }
+
+       if (length < sizeof(struct canmsg_t)) {
+               DEBUGMSG("Trying to read less bytes than a CAN message, \n");
+               DEBUGMSG("this will always return zero.\n");
+               return 0;
+       }
+
+       qends = canuser->qends;
+
+       /*if (((struct canmsg_t *)buffer)->flags & MSG_RTR)
+               ret = can_rtr_read(chip, obj, buffer);
+       else*/
+               ret = can_std_read_rtl(qends, fptr->f_flags & O_NONBLOCK,
+                       buffer, length);
+
+       return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
+
index 1869c9750940d8ad13b329315bf444d819e5c80c..1760bc2fdba740085e9b4f876414dfe4771010c7 100644 (file)
@@ -20,10 +20,10 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
        struct canque_edge_t *qedge;
        struct canque_slot_t *slot;
        int ret = 0;
-       int bytes_to_copy = 0;
+       unsigned bytes_to_copy;
 
        if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
-               CANMSG("can_close: bad canuser magic\n");
+               CANMSG("can_write: bad canuser magic\n");
                return -ENODEV;
        }
 
@@ -32,7 +32,7 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
                DEBUGMSG("this will always return 0 !\n");
                return 0;
        }
-       if (length > 8 * sizeof(struct canmsg_t)) {
+       if (length > INT_MAX) {
                CANMSG("Trying to write more than is supported.\n");
                return -1;
        }
@@ -85,7 +85,8 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
        /* 
         * Try to send more messages
         */
-       while (bytes_to_copy > 0) {
+       while (bytes_to_copy >= sizeof(struct canmsg_t)) {
+               bytes_to_copy -= sizeof(struct canmsg_t);
                /* Prepare first message */
                copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
                /* Automatic selection of extended format if "extended" set and ID>2047 */
@@ -96,7 +97,6 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
                slot->msg=msg_buff;
                canque_put_inslot(qends, qedge, slot);
                buffer += sizeof(struct canmsg_t);
-               bytes_to_copy -= sizeof(struct canmsg_t);
        }
 
         if(file->f_flags & O_SYNC) {
diff --git a/lincan/src/write_rtl.c b/lincan/src/write_rtl.c
new file mode 100644 (file)
index 0000000..a1d4647
--- /dev/null
@@ -0,0 +1,101 @@
+/* write.c
+ * Linux CAN-bus device 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer,
+                                size_t length, loff_t *ppos)
+{
+       struct canuser_t *canuser =
+               (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+       const struct canmsg_t *msg_buff = (struct canmsg_t *)buffer;
+       struct canque_ends_t *qends;
+       struct canque_edge_t *qedge;
+       struct canque_slot_t *slot;
+       int      msg_flags;
+       int      ret;
+       size_t   bytes_to_copy;
+
+       if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+               CANMSG("can_write_rtl_posix: bad canuser magic\n");
+               return -ENODEV;
+       }
+
+       if (length < sizeof(struct canmsg_t)) {
+               DEBUGMSG("Trying to write less bytes than a CAN message,\n");
+               DEBUGMSG("this will always return 0 !\n");
+               return 0;
+       }
+       if (length > INT_MAX) {
+               CANMSG("Trying to write more than is supported.\n");
+               return -1;
+       }
+
+       qends = canuser->qends;
+
+       msg_flags=msg_buff->flags;
+       /* Automatic selection of extended format if "extended" set and ID>2047 */
+       if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT;
+
+       /* If the output buffer is full, return immediately in case O_NONBLOCK
+        * has been specified or loop until space becomes available.
+        */
+       if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
+                       0, msg_buff->id, 0))<0){
+               DEBUGMSG("Buffer is full\n");
+               if(ret < -1)
+                       return -EIO;
+
+               if (fptr->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               ret=canque_get_inslot4id_wait_rtl(qends, &qedge, &slot, 
+                                               0, msg_buff->id, 0);
+               if (ret == -1)
+                       return -EINTR;
+               
+               if(ret<0) {
+                       return -EIO;
+               }
+       }
+       slot->msg=*(msg_buff++);
+       slot->msg.flags=msg_flags;
+       canque_put_inslot(qends, qedge, slot);
+       bytes_to_copy = length-sizeof(struct canmsg_t);
+
+       /* 
+        * Try to send more messages
+        */
+       while (bytes_to_copy >= sizeof(struct canmsg_t)) {
+               bytes_to_copy -= sizeof(struct canmsg_t);
+               msg_flags=msg_buff->flags;
+               /* Automatic selection of extended format if "extended" set and ID>2047 */
+               if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT;
+               /* Get slot */
+               if(canque_get_inslot4id(qends, &qedge, &slot, 
+                       0, msg_buff->id, 0) < 0) break;
+               slot->msg=*(msg_buff++);
+               slot->msg.flags=msg_flags;
+               canque_put_inslot(qends, qedge, slot);
+       }
+
+        if(fptr->f_flags & O_SYNC) {
+               canque_sync_wait_rtl(qends, qedge);
+       }
+       return length-bytes_to_copy;
+}      
+
+#endif /*CAN_WITH_RTL*/