Setup tested to work with Virtual and PCM3680 boards now.
* @flist: pointer to list of the free slots associated with queue
* @entry: pointer to the memory allocated for the list slots.
* @fifo_lock: the lock to ensure atomicity of slot manipulation operations.
+ * @slotnr: number of allocated slots
*
* This structure represents CAN FIFO queue. It is implemented as
* a single linked list of slots prepared for processing. The empty slots
struct canque_slot_t *flist; /* points the first entry in the free list */
struct canque_slot_t *entry; /* points to first allocated entry */
can_spinlock_t fifo_lock; /* can_spin_lock_irqsave / can_spin_unlock_irqrestore */
+ int slotsnr;
};
#define CAN_FIFOF_DESTROY_b 15
#define CAN_FIFOF_INACTIVE_b 7
#define CAN_FIFOF_FREEONEMPTY_b 6
#define CAN_FIFOF_READY_b 5
+#define CAN_FIFOF_NOTIFYPEND_b 4
+#define CAN_FIFOF_RTL_MEM_b 3
#define CAN_FIFOF_DESTROY (1<<CAN_FIFOF_DESTROY_b)
#define CAN_FIFOF_ERROR (1<<CAN_FIFOF_ERROR_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 CAN_FIFOF_NOTIFYPEND (1<<CAN_FIFOF_NOTIFYPEND_b)
+#define CAN_FIFOF_RTL_MEM (1<<CAN_FIFOF_RTL_MEM_b)
#define canque_fifo_test_fl(fifo,fifo_fl) \
test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
can_spin_irqflags_t flags;
slot->next=NULL;
can_spin_lock_irqsave(&fifo->fifo_lock, flags);
- if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
+ if(*fifo->tail) can_printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
*fifo->tail=slot;
fifo->tail=&slot->next;
ret=0;
int canque_fifo_flush_slots(struct canque_fifo_t *fifo);
-int canque_fifo_init_slots(struct canque_fifo_t *fifo, int slotsnr);
-
-int canque_fifo_done(struct canque_fifo_t *fifo);
+int canque_fifo_init_slots(struct canque_fifo_t *fifo);
#define CANQUEUE_PRIO_NR 3
* @edge_used: the atomic usage counter, mainly used for safe destruction of the edge.
* @edge_prio: the assigned queue priority from the range 0 to %CANQUEUE_PRIO_NR-1
* @edge_num: edge sequential number intended for debugging purposes only
+ * @pending_peers: edges with pending delayed events (RTL->Linux calls)
+ * @pending_inops: bitmask of pending operations
+ * @pending_outops: bitmask of pending operations
*
* This structure represents one direction connection from messages source
* (@inends) to message consumer (@outends) fifo ends hub. The edge contains
atomic_t edge_used;
int edge_prio;
int edge_num;
+ #ifdef CAN_WITH_RTL
+ struct list_head pending_peers;
+ unsigned long pending_inops;
+ unsigned long pending_outops;
+ #endif /*CAN_WITH_RTL*/
};
/**
* @context: space to store ends user specific information
* @endinfo: space to store some other ends usage specific informations
* mainly for waking-up by the notify calls.
+ * @dead_peers: used to chain ends wanting for postponed destruction
*
* Structure represents place to connect edges to for CAN communication entity.
* The zero, one or more incoming and outgoing edges can be connected to
struct fasync_struct *fasync;
#endif /*CAN_ENABLE_KERN_FASYNC*/
} fileinfo;
+ #ifdef CAN_WITH_RTL
+ struct {
+ rtl_spinlock_t rtl_lock;
+ rtl_wait_t rtl_readq;
+ rtl_wait_t rtl_writeq;
+ rtl_wait_t rtl_emptyq;
+ unsigned long pend_flags;
+ } rtlinfo;
+ #endif /*CAN_WITH_RTL*/
struct {
- wait_queue_head_t daemonq;
struct msgobj_t *msgobj;
struct chip_t *chip;
+ #ifndef CAN_WITH_RTL
+ wait_queue_head_t daemonq;
+ #else /*CAN_WITH_RTL*/
+ pthread_t worker_thread;
+ #endif /*CAN_WITH_RTL*/
} chipinfo;
} endinfo;
struct list_head dead_peers;
#define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
#define CANQUEUE_NOTIFY_ERRTX_BUS 0x11003 /* tx bus error */
-#define CAN_ENDSF_DEAD (1<<0)
+#define CAN_ENDSF_DEAD (1<<0)
+#define CAN_ENDSF_MEM_RTL (1<<1)
/**
* canque_notify_inends - request to send notification to the input ends
/* Linux kernel specific functions */
+int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr);
+
+int canque_fifo_done_kern(struct canque_fifo_t *fifo);
+
struct canque_edge_t *canque_new_edge_kern(int slotsnr);
int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync);
+void canqueue_ends_dispose_postpone(struct canque_ends_t *qends);
+
void canqueue_kern_initialize(void);
+#ifdef CAN_WITH_RTL
+/* RT-Linux specific functions */
+
+void canqueue_rtl_initialize(void);
+void canqueue_rtl_done(void);
+
+int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
+ struct canque_edge_t *qedge, int what);
+
+struct canque_edge_t *canque_new_edge_rtl(int slotsnr);
+
+void canque_dispose_edge_rtl(struct canque_edge_t *qedge);
+
+void canque_ends_free_rtl(struct canque_ends_t *qends);
+
+int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync);
+
+#else /*CAN_WITH_RTL*/
+
+static inline int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
+ struct canque_edge_t *qedge, int what) { return 0; }
+
+#endif /*CAN_WITH_RTL*/
+
#endif /*_CAN_QUEUE_H*/
#ifndef _CAN_SYSDEP_H
#define _CAN_SYSDEP_H
+#ifdef CAN_WITH_RTL
+#include <rtl.h>
+#include <rtl_sync.h>
+#include <rtl_core.h>
+#include <rtl_mutex.h>
+#include <rtl_sched.h>
+#endif /*CAN_WITH_RTL*/
+
/*#define __NO_VERSION__*/
/*#include <linux/module.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>
#endif /* Linux kernel < 2.5.7 or >= 2.6.0 */
-
+#ifndef CAN_WITH_RTL
#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)
+ typedef void can_irqreturn_t;
+ #define CAN_IRQ_NONE
+ #define CAN_IRQ_HANDLED
+ #define CAN_IRQ_RETVAL(x)
+#else /* <=2.5.67 */
+ typedef irqreturn_t can_irqreturn_t;
+ #define CAN_IRQ_NONE IRQ_NONE
+ #define CAN_IRQ_HANDLED IRQ_HANDLED
+ #define CAN_IRQ_RETVAL IRQ_RETVAL
#endif /* <=2.5.67 */
+#else /*CAN_WITH_RTL*/
+ typedef int can_irqreturn_t;
+ #define CAN_IRQ_NONE 0
+ #define CAN_IRQ_HANDLED 1
+ #define CAN_IRQ_RETVAL(x) ((x) != 0)
+#endif /*CAN_WITH_RTL*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
#define can_synchronize_irq(irqnum) synchronize_irq()
#define CAN_ENABLE_KERN_FASYNC
#ifndef CAN_WITH_RTL
+/* Standard LINUX kernel */
#define can_spinlock_t spinlock_t
#define can_spin_irqflags_t unsigned long
#define can_spin_unlock_irqrestore spin_unlock_irqrestore
#define can_spin_lock_init spin_lock_init
+#if defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+#define can_preempt_disable preempt_disable
+#define can_preempt_enable preempt_enable
+#else /*CONFIG_PREEMPT*/
+#define can_preempt_disable() do { } while (0)
+#define can_preempt_enable() do { } while (0)
+#endif /*CONFIG_PREEMPT*/
+
+#define can_enable_irq enable_irq
+#define can_disable_irq disable_irq
+
+#define can_printk printk
+
#else /*CAN_WITH_RTL*/
#define can_spinlock_t rtl_spinlock_t
#define can_spin_unlock_irqrestore rtl_spin_unlock_irqrestore
#define can_spin_lock_init rtl_spin_lock_init
+#define can_preempt_disable() do { } while (0)
+#define can_preempt_enable() do { } while (0)
+
+#define can_enable_irq rtl_hard_enable_irq
+#define can_disable_irq rtl_hard_disable_irq
+
+#define can_printk rtl_printf
+
#endif /*CAN_WITH_RTL*/
#endif /*_CAN_SYSDEP_H*/
#define MAX_BUF_LENGTH 64
//#define MAX_BUF_LENGTH 4
-#define IE (1<<1)
-#define SIE (1<<2)
-#define EIE (1<<3)
/* These flags can be used for the msgobj_t structure flags data entry */
-#define OBJ_OPENED (1<<0)
-#define OBJ_BUFFERS_ALLOCATED (1<<1)
-#define OBJ_TX_REQUEST (1<<2)
-#define OBJ_TX_LOCK (1<<3)
+#define MSGOBJ_OPENED_b 0
+#define MSGOBJ_TX_REQUEST_b 1
+#define MSGOBJ_TX_LOCK_b 2
+#define MSGOBJ_IRQ_REQUEST_b 3
+#define MSGOBJ_WORKER_WAKE_b 4
+
+#define MSGOBJ_OPENED (1<<MSGOBJ_OPENED_b)
+#define MSGOBJ_TX_REQUEST (1<<MSGOBJ_TX_REQUEST_b)
+#define MSGOBJ_TX_LOCK (1<<MSGOBJ_TX_LOCK_b)
+#define MSGOBJ_IRQ_REQUEST (1<<MSGOBJ_IRQ_REQUEST_b)
+#define MSGOBJ_WORKER_WAKE (1<<MSGOBJ_WORKER_WAKE_b)
+
+#define can_msgobj_test_fl(obj,obj_fl) \
+ test_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_set_fl(obj,obj_fl) \
+ set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_clear_fl(obj,obj_fl) \
+ clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_test_and_set_fl(obj,obj_fl) \
+ test_and_set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_test_and_clear_fl(obj,obj_fl) \
+ test_and_clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+
/* These flags can be used for the chip_t structure flags data entry */
#define CHIP_CONFIGURED (1<<0)
int i82527_start_chip(struct chip_t *chip);
int i82527_stop_chip(struct chip_t *chip);
int i82527_check_tx_stat(struct chip_t *chip);
-irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+can_irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
#define MSG_OFFSET(object) ((object)*0x10)
* Version lincan-0.2 9 Jul 2003
*/
-irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+can_irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+can_irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+can_irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
#include "./can_queue.h"
#ifdef CAN_DEBUG
- #define DEBUGMSG(fmt,args...) printk(KERN_ERR "can.o (debug): " fmt,\
+ #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "can.o (debug): " fmt,\
##args)
#else
#define DEBUGMSG(fmt,args...)
#endif
-#define CANMSG(fmt,args...) printk(KERN_ERR "can.o: " fmt,##args)
+#define CANMSG(fmt,args...) can_printk(KERN_ERR "can.o: " fmt,##args)
/**
struct candevice_t *hostdevice;
int max_objects; /* 1 for sja1000, 15 for i82527 */
+
+ #ifdef CAN_WITH_RTL
+ pthread_t worker_thread;
+ rtl_spinlock_t rtl_lock;
+ unsigned long pend_flags;
+ #endif /*CAN_WITH_RTL*/
};
/**
unsigned long obj_base_addr;
unsigned int minor; /* associated device minor number */
unsigned int object; /* object number in chip_t +1 for debug printk */
- unsigned long flags;
+ unsigned long obj_flags;
int ret;
struct canque_ends_t *qends;
unsigned short btr1);
int (*start_chip)(struct chip_t *chip);
int (*stop_chip)(struct chip_t *chip);
- irqreturn_t (*irq_handler)(int irq, void *dev_id, struct pt_regs *regs);
+ can_irqreturn_t (*irq_handler)(int irq, void *dev_id, struct pt_regs *regs);
};
struct mem_addr {
void *can_checked_malloc(size_t size);
int can_checked_free(void *address_p);
int can_del_mem_list(void);
+int can_chip_setup_irq(struct chip_t *chip);
+void can_chip_free_irq(struct chip_t *chip);
unsigned short btr1);
int sja1000_start_chip(struct chip_t *chip);
int sja1000_stop_chip(struct chip_t *chip);
-irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+can_irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
/* BasicCAN mode address map */
#define SJACR 0x00 /* Control register */
-rtlinux_INCLUDES = -I $(srcdir)/../include
+rtlinux_INCLUDES = -I $(srcdir)/../include -DCAN_WITH_RTL
kernel_INCLUDES = -I $(srcdir)/../include
-#kernel_INCLUDES += -DCAN_DEBUG
+kernel_INCLUDES += -DCAN_DEBUG
kernel_INCLUDES += -DWITH_DEVFS_FS
kernel_MODULES = lincan
pc_i03.c pcm3680.c aim104.c m437.c pcccan.c ssv.c \
bfadcan.c pikronisa.c virtual.c template.c
-lincan_SOURCES = can_queue.c can_quekern.c devcommon.c main.c modparms.c \
- setup.c finish.c irq.c boardlist.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)
+
int aim104_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
+ chip->msgobj[objnr]->obj_flags=0;
return 0;
}
int bfadcan_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
--- /dev/null
+/* can_devrtl.c - CAN message queues functions for the RT-Linux
+ * 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/can_queue.h"
+#include "../include/main.h"
+#include "../include/setup.h"
+
+#include <rtl_malloc.h>
+
+unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
+{
+ struct chip_t *chip;
+ struct candevice_t *candev;
+ int board_nr;
+ int chip_nr;
+ pthread_t thread=NULL;
+
+ DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
+
+ /* I hate next loop, but RT-Linux does not provide context to ISR */
+ for (board_nr=hardware_p->nr_boards; board_nr--; ) {
+ if((candev=hardware_p->candevice[board_nr])==NULL)
+ continue;
+ for(chip_nr=candev->nr_all_chips; chip_nr--; ) {
+ if((chip=candev->chip[chip_nr])==NULL)
+ continue;
+ if(chip->chip_irq!=irq_num) continue;
+
+ set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
+ set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
+
+ if(!chip->worker_thread) continue;
+ thread=chip->worker_thread;
+ pthread_kill(thread,RTL_SIGNAL_WAKEUP);
+ }
+ }
+
+ /*rtl_global_pend_irq(irq_num);*/
+
+ /*if(thread) rtl_reschedule_thread(thread);*/
+
+ rtl_schedule();
+
+ return 0;
+}
+
+
+
+/*
+RTL_MARK_READY(pthread_self())
+RTL_MARK_SUSPENDED(pthread_self());
+return rtl_schedule();
+can_enable_irq
+can_disable_irq
+rtl_critical( state )
+rtl_end_critical( state )
+rtl_request_global_irq( irq, isr );
+rtl_free_global_irq( irq )
+*/
+
+void * can_chip_worker_thread(void *arg)
+{
+ struct chip_t *chip = (struct chip_t *) arg;
+ struct msgobj_t *obj;
+ int ret, i;
+ int loop_cnt;
+
+ if(!chip) return 0;
+
+
+ if (!(chip->flags & CHIP_CONFIGURED)){
+ if (chip->chipspecops->chip_config(chip))
+ CANMSG("Error configuring chip.\n");
+ else
+ chip->flags |= CHIP_CONFIGURED;
+
+ if((chip->msgobj[0])!=NULL)
+ if (chip->chipspecops->pre_read_config(chip,chip->msgobj[0])<0)
+ CANMSG("Error initializing chip for receiving\n");
+
+ } /* End of chip configuration */
+ set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
+
+
+ while (1) {
+ DEBUGMSG("Worker thread for chip %d active\n",chip->chip_idx);
+ if(test_and_clear_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags)){
+ DEBUGMSG("IRQ_REQUEST processing ...\n");
+ loop_cnt = 100;
+ if(chip->chipspecops->irq_handler) do{
+ ret=chip->chipspecops->irq_handler(chip->chip_irq,chip,NULL);
+ }while(ret && --loop_cnt);
+ continue;
+ }
+ if(test_and_clear_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags)){
+ DEBUGMSG("TX_REQUEST processing ...\n");
+ for(i=0;i<chip->max_objects;i++){
+ if((obj=chip->msgobj[i])==NULL)
+ continue;
+ if(!can_msgobj_test_and_clear_fl(obj,TX_REQUEST))
+ continue;
+ DEBUGMSG("Calling wakeup_tx\n");
+ chip->chipspecops->wakeup_tx(chip, obj);
+ }
+ continue;
+ }
+
+ /*re-enable chip IRQ, I am not sure, if this is required,
+ but it seems to not work without that */
+ if(chip->chip_irq>=0)
+ can_enable_irq(chip->chip_irq);
+
+ RTL_MARK_SUSPENDED(pthread_self());
+ if(test_and_clear_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags)){
+ RTL_MARK_READY(pthread_self());
+ continue;
+ }
+ rtl_schedule();
+
+ }
+ return 0;
+}
+
+
+int can_chip_setup_irq(struct chip_t *chip)
+{
+ int ret;
+
+ if(chip==NULL)
+ return -1;
+ if(chip->chipspecops->irq_handler){
+ if (rtl_request_irq(chip->chip_irq,can_rtl_isr))
+ return -1;
+ else {
+ DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
+ chip->flags |= CHIP_IRQ_SETUP;
+ }
+ }
+ ret=pthread_create(&chip->worker_thread, NULL, can_chip_worker_thread, chip);
+ if(ret<0) chip->worker_thread=NULL;
+
+ return ret;
+}
+
+
+void can_chip_free_irq(struct chip_t *chip)
+{
+ if(chip->worker_thread)
+ pthread_delete_np(chip->worker_thread);
+ if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+ rtl_free_irq(chip->chip_irq);
+ chip->flags &= ~CHIP_IRQ_SETUP;
+ }
+}
+
+
+#endif /*CAN_WITH_RTL*/
extern atomic_t edge_num_cnt;
#ifdef CAN_DEBUG
- #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
+ #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
##args)
#else
#define DEBUGQUE(fmt,args...)
#endif
-#define ERRMSGQUE(fmt,args...) printk(KERN_ERR "can_queue: " fmt,\
+#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_queue: " fmt,\
##args)
while((qedge=canque_dead_edges_cut_first())){
DEBUGQUE("edge %d disposed\n",qedge->edge_num);
+ #ifdef CAN_WITH_RTL
+ if(canque_fifo_test_fl(&qedge->fifo,RTL_MEM)){
+ canque_dispose_edge_rtl(qedge);
+ continue;
+ }
+ #endif /*CAN_WITH_RTL*/
+ canque_fifo_done_kern(&qedge->fifo);
kfree(qedge);
}
list_del(&qends->dead_peers);
can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
DEBUGQUE("ends structure disposed\n");
+ #ifdef CAN_WITH_RTL
+ if(qends->ends_flags&CAN_ENDSF_MEM_RTL){
+ canque_ends_free_rtl(qends);
+ continue;
+ }
+ #endif /*CAN_WITH_RTL*/
kfree(qends);
}
{
DEBUGQUE("canqueue_notify_kern for edge %d, use %d and event %d\n",
qedge->edge_num,(int)atomic_read(&qedge->edge_used),what);
+
+ /* delay event delivery for RT-Linux -> kernel notifications */
+ if(canqueue_rtl2lin_check_and_pend(qends,qedge,what)){
+ DEBUGQUE("canqueue_notify_kern postponed\n");
+ return;
+ }
+
switch(what){
case CANQUEUE_NOTIFY_EMPTY:
wake_up(&qends->endinfo.fileinfo.emptyq);
}
+/**
+ * canque_fifo_init_kern - initialize one CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ * @slotsnr: number of requested slots
+ *
+ * Return Value: The negative value indicates, that there is no memory
+ * to allocate space for the requested number of the slots.
+ */
+int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr)
+{
+ int size;
+ if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
+ size=sizeof(struct canque_slot_t)*slotsnr;
+ fifo->entry=kmalloc(size,GFP_KERNEL);
+ if(!fifo->entry) return -1;
+ fifo->slotsnr=slotsnr;
+ return canque_fifo_init_slots(fifo);
+}
+
+/**
+ * canque_fifo_done_kern - frees slots allocated for CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ */
+int canque_fifo_done_kern(struct canque_fifo_t *fifo)
+{
+ if(fifo->entry)
+ kfree(fifo->entry);
+ fifo->entry=NULL;
+ return 1;
+}
+
+
/**
* canque_new_edge_kern - allocate new edge structure in the Linux kernel context
* @slotsnr: required number of slots in the newly allocated edge structure
memset(qedge,0,sizeof(struct canque_edge_t));
can_spin_lock_init(&qedge->fifo.fifo_lock);
- if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){
+ if(canque_fifo_init_kern(&qedge->fifo, slotsnr)<0){
kfree(qedge);
DEBUGQUE("canque_new_edge_kern failed\n");
return NULL;
can_spin_unlock_irqrestore(&qends->ends_lock,flags);
if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
/* Free edge memory */
- canque_fifo_done(&edge->fifo);
+ canque_fifo_done_kern(&edge->fifo);
kfree(edge);
}else{
canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
return 0;
}
+
+void canqueue_ends_dispose_postpone(struct canque_ends_t *qends)
+{
+ can_spin_irqflags_t flags;
+
+ can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+ 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);
+}
+
+
/**
* canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients
* @qends: pointer to ends structure
*/
int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync)
{
- can_spin_irqflags_t flags;
int delayed;
DEBUGQUE("canqueue_ends_dispose_kern\n");
wake_up(&qends->endinfo.fileinfo.emptyq);
if(delayed){
- can_spin_lock_irqsave(&canque_dead_func_lock, flags);
- 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);
+ canqueue_ends_dispose_postpone(qends);
DEBUGQUE("canqueue_ends_dispose_kern delayed\n");
return 1;
--- /dev/null
+/* can_quertl.c - CAN message queues functions for the RT-Linux
+ * 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/can_queue.h"
+
+#include <rtl_malloc.h>
+
+/*
+ * 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;
+
+
+#define CANQUE_PENDOPS_LIMIT 15
+#define CANQUE_PENDOPS_MASK ((1<<CANQUE_PENDOPS_LIMIT)-1)
+
+struct list_head canque_pending_edges_list;
+can_spinlock_t canque_pending_edges_lock;
+
+static int canqueue_rtl_irq = 0;
+
+void
+canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
+{
+ can_spin_irqflags_t flags;
+ struct canque_edge_t *qedge;
+ unsigned pending_inops;
+ unsigned pending_outops;
+ int i;
+
+ can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
+
+ while(!list_empty(&canque_pending_edges_list)){
+ qedge=list_entry(canque_pending_edges_list.next,struct canque_edge_t,pending_peers);
+ list_del(&qedge->pending_peers);
+ canque_fifo_clear_fl(&qedge->fifo, NOTIFYPEND);
+ pending_inops=qedge->pending_inops;
+ qedge->pending_inops=0;
+ pending_outops=qedge->pending_outops;
+ qedge->pending_outops=0;
+ can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
+
+ if(pending_outops & ~CANQUE_PENDOPS_MASK){
+ pending_outops &= CANQUE_PENDOPS_MASK;
+ canque_notify_outends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
+ }
+ for(i=0;pending_outops;i++,pending_outops>>=1){
+ if(pending_outops&1)
+ canque_notify_outends(qedge,i);
+ }
+ if(pending_inops & ~CANQUE_PENDOPS_MASK){
+ pending_inops &= CANQUE_PENDOPS_MASK;
+ canque_notify_inends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
+ }
+ for(i=0;pending_inops;i++,pending_inops>>=1){
+ if(pending_inops&1)
+ canque_notify_inends(qedge,i);
+ }
+
+ canque_edge_decref(qedge);
+ can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
+ }
+
+ can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
+
+ return;
+}
+
+
+/**
+ * canqueue_rtl2lin_check_and_pend - postpones edge notification if called from RT-Linux
+ * @qends: notification target ends
+ * @qedge: edge delivering notification
+ * @what: notification type
+ *
+ * Return Value: if called from Linux context, returns 0 and lefts notification processing
+ * on caller responsibility. If called from RT-Linux contexts, schedules postponed
+ * event delivery and returns 1
+ */
+int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
+ struct canque_edge_t *qedge, int what)
+{
+ can_spin_irqflags_t flags;
+
+ if(rtl_rt_system_is_idle()) return 0;
+
+ can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
+
+ if(what>CANQUE_PENDOPS_LIMIT) what=CANQUE_PENDOPS_LIMIT;
+
+ if(qends == qedge->inends) {
+ set_bit(what,&qedge->pending_inops);
+ } else if(qends == qedge->outends) {
+ set_bit(what,&qedge->pending_outops);
+ }
+
+ if(!canque_fifo_test_and_set_fl(&qedge->fifo, NOTIFYPEND)){
+ canque_edge_incref(qedge);
+ list_add_tail(&qedge->pending_peers,&canque_pending_edges_list);
+ rtl_global_pend_irq (canqueue_rtl_irq);
+ }
+
+ can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
+
+ return 1;
+
+}
+
+
+/**
+ * canque_fifo_init_rtl - initialize one CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ * @slotsnr: number of requested slots
+ *
+ * Return Value: The negative value indicates, that there is no memory
+ * to allocate space for the requested number of the slots.
+ */
+int canque_fifo_init_rtl(struct canque_fifo_t *fifo, int slotsnr)
+{
+ int size;
+ if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
+ size=sizeof(struct canque_slot_t)*slotsnr;
+ fifo->entry=rt_malloc(size);
+ if(!fifo->entry) return -1;
+ fifo->slotsnr=slotsnr;
+ return canque_fifo_init_slots(fifo);
+}
+
+/**
+ * canque_fifo_done_rtl - frees slots allocated for CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ */
+int canque_fifo_done_rtl(struct canque_fifo_t *fifo)
+{
+ if(fifo->entry)
+ rt_free(fifo->entry);
+ fifo->entry=NULL;
+ return 1;
+}
+
+void canque_dispose_edge_rtl(struct canque_edge_t *qedge)
+{
+ canque_fifo_done_rtl(&qedge->fifo);
+ rt_free(qedge);
+}
+
+/**
+ * canque_new_edge_rtl - allocate new edge structure in the RT-Linux 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_rtl(int slotsnr)
+{
+ struct canque_edge_t *qedge;
+ qedge = (struct canque_edge_t *)rt_malloc(sizeof(struct canque_edge_t));
+ if(qedge == NULL) return NULL;
+
+ memset(qedge,0,sizeof(struct canque_edge_t));
+ can_spin_lock_init(&qedge->fifo.fifo_lock);
+ canque_fifo_set_fl(&qedge->fifo,RTL_MEM);
+ if(canque_fifo_init_rtl(&qedge->fifo, slotsnr)<0){
+ rt_free(qedge);
+ 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;
+ #if defined(CAN_DEBUG) && 0
+ /* not exactly clean, but enough for debugging */
+ atomic_inc(&edge_num_cnt);
+ qedge->edge_num=atomic_read(&edge_num_cnt);
+ #endif /* CAN_DEBUG */
+ return qedge;
+}
+
+void canque_ends_free_rtl(struct canque_ends_t *qends)
+{
+ rt_free(qends);
+}
+
+
+/**
+ * canqueue_notify_rtl - 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_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
+{
+ rtl_irqstate_t flags;
+
+ switch(what){
+ case CANQUEUE_NOTIFY_EMPTY:
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ 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))
+ canque_edge_decref(qedge);
+ break;
+ case CANQUEUE_NOTIFY_SPACE:
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ 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);
+ 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);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
+ rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ 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_rtl - RT-Linux clients specific ends initialization
+ * @qends: pointer to the callback side ends structure
+ */
+int canqueue_ends_init_rtl(struct canque_ends_t *qends)
+{
+ canqueue_ends_init_gen(qends);
+ qends->context=NULL;
+ rtl_spin_lock_init(&(qends->endinfo.rtlinfo.rtl_lock));
+ rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_readq));
+ rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_writeq));
+ rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_emptyq));
+
+ qends->notify=canqueue_notify_rtl;
+ return 0;
+}
+
+/**
+ * canqueue_ends_dispose_rtl - 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_rtl(struct canque_ends_t *qends, int sync)
+{
+ rtl_irqstate_t flags;
+ int delayed;
+
+ canqueue_block_inlist(qends);
+ canqueue_block_outlist(qends);
+
+ /*Wait for sending of all pending messages in the output FIFOs*/
+ /*if(sync)
+ canqueue_ends_sync_all_rtl(qends);*/
+
+ /* Finish or kill all outgoing edges listed in inends */
+ delayed=canqueue_ends_kill_inlist(qends, 1);
+ /* Kill all incoming edges listed in outends */
+ delayed|=canqueue_ends_kill_outlist(qends);
+
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
+ rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
+ rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+
+ if(delayed || !(qends->ends_flags&CAN_ENDSF_MEM_RTL)){
+ canqueue_ends_dispose_postpone(qends);
+
+ return 1;
+ }
+
+ canque_ends_free_rtl(qends);
+ return 0;
+}
+
+
+
+void canqueue_rtl_initialize(void)
+{
+ INIT_LIST_HEAD(&canque_pending_edges_list);
+ can_spin_lock_init(&canque_pending_edges_lock);
+
+ canqueue_rtl_irq = rtl_get_soft_irq (canqueue_rtl2lin_handler, "rtl_canqueue_irq");
+}
+
+
+void canqueue_rtl_done(void)
+{
+ rtl_free_soft_irq (canqueue_rtl_irq);
+
+}
+
+
+#endif /*CAN_WITH_RTL*/
atomic_t edge_num_cnt;
//#define CAN_DEBUG
+#undef CAN_DEBUG
#ifdef CAN_DEBUG
- #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
+ #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
##args)
#else
/**
- * canque_fifo_init_slots - initialize one CAN FIFO
+ * canque_fifo_init_slots - initializes slot chain of one CAN FIFO
* @fifo: pointer to the FIFO structure
- * @slotsnr: number of requested slots
*
* Return Value: The negative value indicates, that there is no memory
* to allocate space for the requested number of the slots.
*/
-int canque_fifo_init_slots(struct canque_fifo_t *fifo, int slotsnr)
+int canque_fifo_init_slots(struct canque_fifo_t *fifo)
{
- int size;
struct canque_slot_t *slot;
- if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
- size=sizeof(struct canque_slot_t)*slotsnr;
- fifo->entry=kmalloc(size,GFP_KERNEL);
- if(!fifo->entry) return -1;
+ int slotsnr=fifo->slotsnr;
+ if(!fifo->entry || !slotsnr) return -1;
slot=fifo->entry;
fifo->flist=slot;
while(--slotsnr){
return 1;
}
-/**
- * canque_fifo_done - frees slots allocated for CAN FIFO
- * @fifo: pointer to the FIFO structure
- */
-int canque_fifo_done(struct canque_fifo_t *fifo)
-{
- if(fifo->entry)
- kfree(fifo->entry);
- fifo->entry=NULL;
- return 1;
-}
-
/* atomic_dec_and_test(&qedge->edge_used);
void atomic_inc(&qedge->edge_used);
list_add_tail(struct list_head *new, struct list_head *head)
int cc104_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
return 0;
}
kfree(canuser);
if(atomic_dec_and_test(&obj->obj_used)){
- obj->flags &= ~OBJ_OPENED;
+ can_msgobj_clear_fl(obj,OPENED);
/* FIXME: what about clearing chip HW status, stopping sending messages etc? */
};
wake_up(&qends->endinfo.chipinfo.daemonq);
break;*/
case CANQUEUE_NOTIFY_PROC:
+ #ifndef CAN_WITH_RTL
/*wake_up(&qends->endinfo.chipinfo.daemonq);*/
chip->chipspecops->wakeup_tx(chip, obj);
+ #else /*CAN_WITH_RTL*/
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ if(qends->endinfo.chipinfo.worker_thread){
+ can_msgobj_set_fl(obj,WORKER_WAKE);
+ pthread_kill(qends->endinfo.chipinfo.worker_thread,RTL_SIGNAL_WAKEUP);
+ rtl_schedule();
+ } else {
+ set_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags);
+
+ if(chip->worker_thread) {
+ set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
+ pthread_kill(chip->worker_thread,RTL_SIGNAL_WAKEUP);
+ rtl_schedule();
+ }
+ }
+ #endif /*CAN_WITH_RTL*/
break;
case CANQUEUE_NOTIFY_DEAD_WANTED:
case CANQUEUE_NOTIFY_DEAD:
if(ret<0) return ret;
qends->context=NULL;
+ #ifndef CAN_WITH_RTL
init_waitqueue_head(&qends->endinfo.chipinfo.daemonq);
+ #endif /*CAN_WITH_RTL*/
qends->endinfo.chipinfo.chip=chip;
qends->endinfo.chipinfo.msgobj=obj;
qends->notify=canqueue_notify_chip;
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_chip_free_irq(chip);
can_synchronize_irq(chip->chip_irq);
}
}
-irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+can_irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int id0=0, id1=0, id2=0, id3=0;
if (irq_register == 0x01) {
DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT));
- return IRQ_NONE;
+ return CAN_IRQ_NONE;
}
if (irq_register == 0x02)
obj=chip->msgobj[object];
if (canobj_read_reg(chip,obj,iMSGCFG) & MCFG_DIR) {
- set_bit(OBJ_TX_REQUEST,&obj->flags);
- while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
- clear_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
i82527_irq_write_handler(chip, obj);
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
}
}
else {
irq_register=i82527_seg_read_reg(chip, iIRQ);
}
- return IRQ_HANDLED;
+ return CAN_IRQ_HANDLED;
}
void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj,
int i82527_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
{
- /* dummy lock to prevent preemption fully portable way */
- can_spinlock_t dummy_lock;
+ can_preempt_disable();
- /* preempt_disable() */
- can_spin_lock_init(&dummy_lock);
- can_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);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
i82527_irq_write_handler(chip, obj);
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
}
- /* preempt_enable(); */
- can_spin_unlock(&dummy_lock);
+ can_preempt_enable();
return 0;
}
#include "../include/irq.h"
-irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
+can_irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
CANMSG("dummy_irq_handler called irq %d \n", irq);
- return IRQ_NONE;
+ return CAN_IRQ_NONE;
}
int m437_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
return -ENODEV;
}
+ #ifdef CAN_WITH_RTL
+ canqueue_rtl_initialize();
+ #endif /*CAN_WITH_RTL*/
+
for (i=0; i<hardware_p->nr_boards; i++) {
candev=hardware_p->candevice[i];
if (candev->hwspecops->request_io(candev))
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))
+ if(can_chip_setup_irq(chip)<0) {
+ CANMSG("IRQ setup failed\n");
goto interrupt_error;
- else {
- DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
- chip->flags |= CHIP_IRQ_SETUP;
}
}
memory_error: ;
canhardware_done(hardware_p);
+ #ifdef CAN_WITH_RTL
+ canqueue_rtl_done();
+ #endif /*CAN_WITH_RTL*/
+
res=unregister_chrdev(major,DEVICE_NAME);
if (res<0)
CANMSG("Error unloading CAN driver, error: %d\n",res);
canhardware_done(hardware_p);
+ #ifdef CAN_WITH_RTL
+ canqueue_rtl_done();
+ #endif /*CAN_WITH_RTL*/
+
if ( can_del_mem_list() )
CANMSG("Error deallocating memory\n");
chip->msgobj[objnr]->obj_base_addr=
chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
data */
unsigned char ret;
- disable_irq(nsican_irq);
+ can_disable_irq(nsican_irq);
outb(address-nsican_base, nsican_base);
ret=inb(nsican_base+1);
- enable_irq(nsican_irq);
+ can_enable_irq(nsican_irq);
return ret;
}
atomic_inc(&obj->obj_used);
DEBUGMSG("Device %d opened %d times.\n", MINOR_NR, atomic_read(&obj->obj_used));
- obj->flags |= OBJ_OPENED;
+ can_msgobj_set_fl(obj,OPENED);
if (chip->flags & CHIP_CONFIGURED)
DEBUGMSG("Device is already configured.\n");
if (chip->chipspecops->pre_read_config(chip,obj)<0)
CANMSG("Error initializing chip for receiving\n");
- /* chip->flags |= OBJ_BUFFERS_ALLOCATED; */
-
} /* End of chip configuration */
canuser = (struct canuser_t *)kmalloc(sizeof(struct canuser_t), GFP_KERNEL);
int pci03_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
return 0;
}
int i=0,chip_nr=0;
for (i=0; i<4; i++)
- disable_irq(candev->chip[i]->chip_irq);
+ can_disable_irq(candev->chip[i]->chip_irq);
DEBUGMSG("Resetting pccan-q hardware ...\n");
while (i < 100000) {
}
for (i=0; i<4; i++)
- enable_irq(candev->chip[i]->chip_irq);
+ can_enable_irq(candev->chip[i]->chip_irq);
return 0;
}
{
if (!strcmp(chip->chip_type,"sja1000")) {
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
- }
+ }
else { /* The spacing for this card is 0x3c0 */
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10+(int)((objnr+1)/4)*0x3c0;
- chip->msgobj[objnr]->flags=0;
- }
+ }
return 0;
}
int pcccan_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
*/
void pcccan_write_register(unsigned char data, unsigned long address)
{
- disable_irq(pcccan_irq);
+ can_disable_irq(pcccan_irq);
outb(address - pcccan_base, pcccan_base+1);
outb(data, pcccan_base+6);
- enable_irq(pcccan_irq);
+ can_enable_irq(pcccan_irq);
}
/**
unsigned pcccan_read_register(unsigned long address)
{
unsigned ret;
- disable_irq(pcccan_irq);
+ can_disable_irq(pcccan_irq);
outb(address - pcccan_base, pcccan_base+1);
ret=inb(pcccan_base+2);
- enable_irq(pcccan_irq);
+ can_enable_irq(pcccan_irq);
return ret;
}
int pcm3680_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
return 0;
}
int pikronisa_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
return 0;
}
int pip_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
if (candev->hwspecops->init_hw_data(candev))
goto error_nodev;
- if (init_chip_struct(candev))
- goto error_nodev;
+ if ((ret=init_chip_struct(candev)))
+ goto error_chip;
return 0;
error_nodev:
- candevice_done(candev);
ret=-ENODEV;
+ error_chip:
+ candevice_done(candev);
goto error_both;
error_nomem:
*/
int init_chip_struct(struct candevice_t *candev)
{
+ struct chip_t *chip;
static int irq_count=0;
int i=0;
/* Alocate and initialize the chip structures */
for (i=0; i < candev->nr_all_chips; i++) {
candev->chip[i]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t));
- if (candev->chip[i]==NULL)
+ if ((chip=candev->chip[i])==NULL)
return -ENOMEM;
- memset(candev->chip[i], 0, sizeof(struct chip_t));
+ memset(chip, 0, sizeof(struct chip_t));
- candev->chip[i]->write_register=candev->hwspecops->write_register;
- candev->chip[i]->read_register=candev->hwspecops->read_register;
+ chip->write_register=candev->hwspecops->write_register;
+ chip->read_register=candev->hwspecops->read_register;
- candev->chip[i]->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
- if (candev->chip[i]->chipspecops==NULL)
+ chip->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
+ if (chip->chipspecops==NULL)
return -ENOMEM;
-
- 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;
+
+ chips_p[irq_count]=chip;
+ chip->chip_idx=i;
+ chip->hostdevice=candev;
+ chip->chip_irq=irq[irq_count];
+ chip->baudrate=baudrate[irq_count]*1000;
+ if(!chip->baudrate)
+ chip->baudrate=baudrate[0]*1000;
+ chip->flags=0x0;
candev->hwspecops->init_chip_data(candev,i);
if (init_chipspecops(candev,i))
return -ENODEV;
-
- init_obj_struct(candev, candev->chip[i], minor[irq_count]);
+
+ init_obj_struct(candev, chip, minor[irq_count]);
irq_count++;
}
obj->qends=qends;
obj->tx_qedge=NULL;
obj->tx_slot=NULL;
- obj->flags = 0x0;
+ obj->obj_flags = 0x0;
canqueue_ends_init_chip(qends, hostchip, obj);
return 0;
}
+
+#ifndef CAN_WITH_RTL
+
+int can_chip_setup_irq(struct chip_t *chip)
+{
+ if(chip==NULL)
+ return -1;
+ if(!chip->chipspecops->irq_handler)
+ return 0;
+
+ if (request_irq(chip->chip_irq,chip->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chip))
+ return -1;
+ else {
+ DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
+ chip->flags |= CHIP_IRQ_SETUP;
+ }
+ return 1;
+}
+
+
+void can_chip_free_irq(struct chip_t *chip)
+{
+ if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+ free_irq(chip->chip_irq, chip);
+ chip->flags &= ~CHIP_IRQ_SETUP;
+ }
+}
+
+#endif /*CAN_WITH_RTL*/
int i=0;
unsigned flags;
- disable_irq(chip->chip_irq);
+ can_disable_irq(chip->chip_irq);
flags=can_read_reg(chip,SJACR);
}
if (i>=10) {
CANMSG("Reset error\n");
- enable_irq(chip->chip_irq);
+ can_enable_irq(chip->chip_irq);
return -ENODEV;
}
return -ENODEV;
}
- enable_irq(chip->chip_irq);
+ can_enable_irq(chip->chip_irq);
return 0;
}
}
-irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+can_irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned irq_register;
struct chip_t *chip=(struct chip_t *)dev_id;
// can_read_reg(chip, SJASR));
if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0)
- return IRQ_NONE;
+ return CAN_IRQ_NONE;
if ((irq_register & IR_RI) != 0)
sja1000_irq_read_handler(chip, obj);
if ((irq_register & IR_TI) != 0) {
- set_bit(OBJ_TX_REQUEST,&obj->flags);
- while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
- clear_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if (can_read_reg(chip, SJASR) & SR_TBS)
sja1000_irq_write_handler(chip, obj);
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
}
}
}
}
- return IRQ_HANDLED;
+ return CAN_IRQ_HANDLED;
}
void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj)
*/
int sja1000_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
{
- /* dummy lock to prevent preemption fully portable way */
- can_spinlock_t dummy_lock;
+ can_preempt_disable();
- /* preempt_disable() */
- can_spin_lock_init(&dummy_lock);
- can_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);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if (can_read_reg(chip, SJASR) & SR_TBS)
sja1000_irq_write_handler(chip, obj);
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
}
- /* preempt_enable(); */
- can_spin_unlock(&dummy_lock);
+ can_preempt_enable();
return 0;
}
int i=0;
enum sja1000_PeliCAN_MOD flags;
- disable_irq(chip->chip_irq);
+ can_disable_irq(chip->chip_irq);
flags=can_read_reg(chip,SJAMOD);
}
if (i>=10) {
CANMSG("Reset error\n");
- enable_irq(chip->chip_irq);
+ can_enable_irq(chip->chip_irq);
return -ENODEV;
}
return -ENODEV;
}
- enable_irq(chip->chip_irq);
+ can_enable_irq(chip->chip_irq);
return 0;
}
* message queues.
* File: src/sja1000p.c
*/
-irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+can_irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int irq_register, status, error_code;
struct chip_t *chip=(struct chip_t *)dev_id;
// can_read_reg(chip,SJASR));
if ((irq_register & (IR_BEI|IR_EPI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0)
- return IRQ_NONE;
+ return CAN_IRQ_NONE;
- if(!obj->flags & OBJ_BUFFERS_ALLOCATED) {
- CANMSG("sja1000p_irq_handler: called with device closed, irq_register 0x%02x\n", irq_register);
- return IRQ_NONE;
+ if(!(chip->flags&CHIP_CONFIGURED)) {
+ CANMSG("sja1000p_irq_handler: called for non-configured device, irq_register 0x%02x\n", irq_register);
+ return CAN_IRQ_NONE;
}
if ((irq_register & IR_RI) != 0) {
if ((irq_register & IR_TI) != 0) {
DEBUGMSG("sja1000_irq_handler: TI\n");
obj->ret = 0;
- set_bit(OBJ_TX_REQUEST,&obj->flags);
- while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
- clear_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if (can_read_reg(chip, SJASR) & SR_TBS)
sja1000p_irq_write_handler(chip, obj);
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
DEBUGMSG("TX looping in sja1000_irq_handler\n");
}
}
obj->tx_retry_cnt=0;
}
- return IRQ_HANDLED;
+ return CAN_IRQ_HANDLED;
}
/**
*/
int sja1000p_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
{
- /* dummy lock to prevent preemption fully portable way */
- can_spinlock_t dummy_lock;
- /* preempt_disable() */
- can_spin_lock_init(&dummy_lock);
- can_spin_lock(&dummy_lock);
+ can_preempt_disable();
- set_bit(OBJ_TX_REQUEST,&obj->flags);
- while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
- clear_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
if (can_read_reg(chip, SJASR) & SR_TBS){
obj->tx_retry_cnt=0;
sja1000p_irq_write_handler(chip, obj);
}
- clear_bit(OBJ_TX_LOCK,&obj->flags);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
DEBUGMSG("TX looping in sja1000p_wakeup_tx\n");
}
- /* preempt_enable(); */
- can_spin_unlock(&dummy_lock);
+ can_preempt_enable();
return 0;
}
int smartcan_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
void smartcan_write_register(unsigned char data, unsigned long address)
{
- disable_irq(smartcan_irq);
+ can_disable_irq(smartcan_irq);
outb(address-smartcan_base,smartcan_base);
outb(data,smartcan_base+1);
- enable_irq(smartcan_irq);
+ can_enable_irq(smartcan_irq);
}
unsigned smartcan_read_register(unsigned long address)
{
unsigned ret;
- disable_irq(smartcan_irq);
+ can_disable_irq(smartcan_irq);
outb(address-smartcan_base,smartcan_base);
ret=inb(smartcan_base+1);
- enable_irq(smartcan_irq);
+ can_enable_irq(smartcan_irq);
return ret;
}
chip->msgobj[objnr]->obj_base_addr=
chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
if((address-ssvcan_base)<0x100)
{
- disable_irq(ssvcan_irq[0]);
+ can_disable_irq(ssvcan_irq[0]);
outb(address-ssvcan_base, ssvcan_base);
ret=inb(ssvcan_base+1);
- enable_irq(ssvcan_irq[0]);
+ can_enable_irq(ssvcan_irq[0]);
}
else
{
- disable_irq(ssvcan_irq[1]);
+ can_disable_irq(ssvcan_irq[1]);
outb(address-ssvcan_base-0x100, ssvcan_base+0x02);
ret=inb(ssvcan_base+1+0x02);
- enable_irq(ssvcan_irq[1]);
+ can_enable_irq(ssvcan_irq[1]);
}
return ret;
int template_init_obj_data(struct chip_t *chip, int objnr)
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
- chip->msgobj[objnr]->flags=0;
return 0;
}
* message queues.
* File: src/virtual.c
*/
-irqreturn_t virtual_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+can_irqreturn_t virtual_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- return IRQ_HANDLED;
+ return CAN_IRQ_HANDLED;
}
void virtual_schedule_next(struct msgobj_t *obj)
{
int cmd;
- /* dummy lock to prevent preemption fully portable way */
- can_spinlock_t dummy_lock;
- /* preempt_disable() */
- can_spin_lock_init(&dummy_lock);
- can_spin_lock(&dummy_lock);
+ can_preempt_disable();
- set_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_set_fl(obj,TX_REQUEST);
- while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
- clear_bit(OBJ_TX_REQUEST,&obj->flags);
+ can_msgobj_clear_fl(obj,TX_REQUEST);
cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
if(cmd>=0) {
CANMSG("virtual: scheduled delivery\n");
} else
- clear_bit(OBJ_TX_LOCK,&obj->flags);
+ can_msgobj_clear_fl(obj,TX_LOCK);
- if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
DEBUGMSG("TX looping in virtual_schedule_next\n");
}
- /* preempt_enable(); */
- can_spin_unlock(&dummy_lock);
+ can_preempt_enable();
}
obj->tx_slot=NULL;
CANMSG("virtual: delayed delivery\n");
}
- clear_bit(OBJ_TX_LOCK,&obj->flags);
+ can_msgobj_clear_fl(obj,TX_LOCK);
virtual_schedule_next(obj);
}
*/
int virtual_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
{
- /* set_bit(OBJ_TX_REQUEST,&obj->flags); */
+ /* can_msgobj_set_fl(obj,TX_REQUEST); */
struct canque_edge_t *qedge;
struct canque_slot_t *slot;
int cmd;
-
+
+ #ifndef CAN_WITH_RTL
if(!virtual_bus_latency(obj)) {
+ #endif /*CAN_WITH_RTL*/
/* Ensure delivery of all ready slots */
while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
if(cmd==0) {
}
canque_free_outslot(obj->qends, qedge, slot);
}
+ #ifndef CAN_WITH_RTL
} else {
virtual_schedule_next(obj);
}
+ #endif /*CAN_WITH_RTL*/
return 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;