The code has been updated and tested with 2.6.0-test9 as well.
Default asynchronous close does not wait for transmission of the
messages left in the Tx FIFOs. ENDS dispose is delayed in such case.
Virtual chip driver can model bus latency if nonzero baudrate is selected.
#ifndef _CAN_QUEUE_H
#define _CAN_QUEUE_H
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
#include "./can.h"
#include "./constants.h"
-
-/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
- kernels need next definitions too */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
- #define wait_queue_head_t struct wait_queue *
- #define wait_queue_t struct wait_queue
- #define init_waitqueue_head(queue_head) (*queue_head=NULL)
- #define init_waitqueue_entry(qentry,qtask) \
- (qentry->next=NULL,qentry->task=qtask)
- #define DECLARE_WAIT_QUEUE_HEAD(name) \
- struct wait_queue * name=NULL
- #define DECLARE_WAITQUEUE(wait, current) \
- struct wait_queue wait = { current, NULL }
- #define init_MUTEX(sem) (*sem=MUTEX)
- #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-#endif /* 2.2.19 */
-
+#include "./can_sysdep.h"
/**
* struct canque_slot_t - one CAN message slot in the CAN FIFO queue
#define CAN_FIFOF_FULL_b 10
#define CAN_FIFOF_EMPTY_b 9
#define CAN_FIFOF_DEAD_b 8
+#define CAN_FIFOF_INACTIVE_b 7
+#define CAN_FIFOF_FREEONEMPTY_b 6
+#define CAN_FIFOF_READY_b 5
#define CAN_FIFOF_DESTROY (1<<CAN_FIFOF_DESTROY_b)
#define CAN_FIFOF_ERROR (1<<CAN_FIFOF_ERROR_b)
#define CAN_FIFOF_FULL (1<<CAN_FIFOF_FULL_b)
#define CAN_FIFOF_EMPTY (1<<CAN_FIFOF_EMPTY_b)
#define CAN_FIFOF_DEAD (1<<CAN_FIFOF_DEAD_b)
+#define CAN_FIFOF_INACTIVE (1<<CAN_FIFOF_INACTIVE_b)
+#define CAN_FIFOF_FREEONEMPTY (1<<CAN_FIFOF_FREEONEMPTY_b)
+#define CAN_FIFOF_READY (1<<CAN_FIFOF_READY_b)
#define canque_fifo_test_fl(fifo,fifo_fl) \
test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
*fifo->tail=slot;
fifo->tail=&slot->next;
+ ret=0;
if(canque_fifo_test_and_clear_fl(fifo,EMPTY))
ret=CAN_FIFOF_EMPTY; /* Fifo has been empty before put */
- else
- ret=0;
+ if(canque_fifo_test_and_clear_fl(fifo,INACTIVE))
+ ret=CAN_FIFOF_INACTIVE; /* Fifo has been empty before put */
spin_unlock_irqrestore(&fifo->fifo_lock, flags);
return ret;
}
/**
* struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends)
+ * @ends_flags: this field holds flags describing state of the ENDS structure.
* @active: the array of the lists of active edges directed to the ends structure
* with ready messages. The array is indexed by the edges priorities.
* @idle: the list of the edges directed to the ends structure with empty FIFOs.
* this structure.
*/
struct canque_ends_t {
+ unsigned long ends_flags;
struct list_head active[CANQUEUE_PRIO_NR];
struct list_head idle;
struct list_head inlist;
struct chip_t *chip;
} chipinfo;
} endinfo;
+ struct list_head dead_peers;
};
-#define CANQUEUE_NOTIFY_EMPTY 1 /* out -> in - all slots are processed by FIFO out side */
-#define CANQUEUE_NOTIFY_SPACE 2 /* out -> in - full state negated => there is space for new message */
-#define CANQUEUE_NOTIFY_PROC 3 /* in -> out - empty state negated => out side is requested to process slots */
-#define CANQUEUE_NOTIFY_NOUSR 4 /* called with some lock to prevent edge disappear */
-#define CANQUEUE_NOTIFY_DEAD 5 /* */
-#define CANQUEUE_NOTIFY_ATACH 6 /* */
-#define CANQUEUE_NOTIFY_FILTCH 7 /* filter changed */
+#define CANQUEUE_NOTIFY_EMPTY 1 /* out -> in - all slots are processed by FIFO out side */
+#define CANQUEUE_NOTIFY_SPACE 2 /* out -> in - full state negated => there is space for new message */
+#define CANQUEUE_NOTIFY_PROC 3 /* in -> out - empty state negated => out side is requested to process slots */
+#define CANQUEUE_NOTIFY_NOUSR 4 /* called with some lock to prevent edge disappear */
+#define CANQUEUE_NOTIFY_DEAD 5 /* */
+#define CANQUEUE_NOTIFY_DEAD_WANTED 6 /* */
+#define CANQUEUE_NOTIFY_ATTACH 7 /* */
+#define CANQUEUE_NOTIFY_FILTCH 8 /* filter changed */
#define CANQUEUE_NOTIFY_ERROR 0x10000 /* error notifiers */
#define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */
#define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
#define CANQUEUE_NOTIFY_ERRTX_BUS 0x11003 /* tx bus error */
+#define CAN_ENDSF_DEAD (1<<0)
+
/**
* canque_notify_inends - request to send notification to the input ends
* @qedge: pointer to the edge structure
int canque_flush(struct canque_edge_t *qedge);
+int canqueue_disconnect_edge(struct canque_edge_t *qedge);
+
+int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+
+int canqueue_ends_init_gen(struct canque_ends_t *qends);
+
+
+/* edge reference and traversal functions */
+
+void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl);
+
+static inline
+void canque_edge_incref(struct canque_edge_t *edge)
+{
+ atomic_inc(&edge->edge_used);
+}
+
+static inline
+void canque_edge_decref(struct canque_edge_t *edge)
+{
+ unsigned long flags;
+ struct canque_ends_t *inends=edge->inends;
+ struct canque_ends_t *outends=edge->outends;
+ int dead_fl;
+
+ spin_lock_irqsave(&inends->ends_lock, flags);
+ spin_lock(&outends->ends_lock);
+ if(atomic_dec_and_test(&edge->edge_used)) {
+ dead_fl=canque_fifo_test_and_set_fl(&edge->fifo,DEAD);
+ /*This should not be there, but it cannot be outside of the lock :-(*/
+ canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+ spin_unlock(&outends->ends_lock);
+ spin_unlock_irqrestore(&inends->ends_lock, flags);
+ canque_edge_do_dead(edge, dead_fl);
+ } else {
+ spin_unlock(&outends->ends_lock);
+ spin_unlock_irqrestore(&inends->ends_lock, flags);
+ }
+}
+
+static inline
+struct canque_edge_t *canque_first_inedge(struct canque_ends_t *qends)
+{
+ unsigned long flags;
+ struct list_head *entry;
+ struct canque_edge_t *edge;
+
+ spin_lock_irqsave(&qends->ends_lock, flags);
+ entry=qends->inlist.next;
+ skip_dead:
+ if(entry != &qends->inlist) {
+ edge=list_entry(entry,struct canque_edge_t,inpeers);
+ if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+ entry=entry->next;
+ goto skip_dead;
+ }
+ canque_edge_incref(edge);
+ } else {
+ edge=NULL;
+ }
+ spin_unlock_irqrestore(&qends->ends_lock, flags);
+ return edge;
+}
+
+
+static inline
+struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct canque_edge_t *edge)
+{
+ unsigned long flags;
+ struct list_head *entry;
+ struct canque_edge_t *next;
+
+ spin_lock_irqsave(&qends->ends_lock, flags);
+ entry=edge->inpeers.next;
+ skip_dead:
+ if(entry != &qends->inlist) {
+ next=list_entry(entry,struct canque_edge_t,inpeers);
+ if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+ entry=entry->next;
+ goto skip_dead;
+ }
+ canque_edge_incref(next);
+ } else {
+ next=NULL;
+ }
+ spin_unlock_irqrestore(&qends->ends_lock, flags);
+ canque_edge_decref(edge);
+ return next;
+}
+
+#define canque_for_each_inedge(qends, edge) \
+ for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge))
+
+/* Linux kernel specific functions */
+
struct canque_edge_t *canque_new_edge_kern(int slotsnr);
int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge);
-int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+int canqueue_ends_init_kern(struct canque_ends_t *qends);
-int canqueue_ends_init_gen(struct canque_ends_t *qends);
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync);
-int canqueue_ends_init_kern(struct canque_ends_t *qends);
+void canqueue_kern_initialize(void);
-int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync);
#endif /*_CAN_QUEUE_H*/
--- /dev/null
+#ifndef _CAN_SYSDEP_H
+#define _CAN_SYSDEP_H
+
+/*#define __NO_VERSION__*/
+/*#include <linux/module.h>*/
+
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+
+/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
+ kernels need next definitions too */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
+ #define wait_queue_head_t struct wait_queue *
+ #define wait_queue_t struct wait_queue
+ #define init_waitqueue_head(queue_head) (*queue_head=NULL)
+ #define init_waitqueue_entry(qentry,qtask) \
+ (qentry->next=NULL,qentry->task=qtask)
+ #define DECLARE_WAIT_QUEUE_HEAD(name) \
+ struct wait_queue * name=NULL
+ #define DECLARE_WAITQUEUE(wait, current) \
+ struct wait_queue wait = { current, NULL }
+ #define init_MUTEX(sem) (*sem=MUTEX)
+ #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+#endif /* 2.2.19 */
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+
+#define MINOR_NR \
+ (MINOR(file->f_dentry->d_inode->i_rdev))
+
+#else /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+#define MINOR_NR \
+ (minor(file->f_dentry->d_inode->i_rdev))
+
+#endif /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
+ typedef void irqreturn_t;
+ #define IRQ_NONE
+ #define IRQ_HANDLED
+ #define IRQ_RETVAL(x)
+#endif /* <=2.5.67 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
+ #define can_synchronize_irq(irqnum) synchronize_irq()
+#else /* >=2.5.33 */
+ #define can_synchronize_irq synchronize_irq
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+ #define del_timer_sync del_timer
+#endif /* <2.4.0 */
+
+#endif /*_CAN_SYSDEP_H*/
#define MAX_MSGOBJS 15
#define MAX_TOT_MSGOBJS (MAX_TOT_CHIPS*MAX_MSGOBJS)
#define MAX_BUF_LENGTH 64
+//#define MAX_BUF_LENGTH 4
#define IE (1<<1)
#define SIE (1<<2)
#define OBJ_TX_LOCK (1<<3)
/* These flags can be used for the chip_t structure flags data entry */
-#define CHIP_CONFIGURED (1<<0)
-#define CHIP_SEGMENTED (1<<1)
+#define CHIP_CONFIGURED (1<<0)
+#define CHIP_SEGMENTED (1<<1)
+#define CHIP_IRQ_SETUP (1<<2)
/* These flags can be used for the candevices_t structure flags data entry */
-#define PROGRAMMABLE_IRQ (1<<0)
+#define CANDEV_PROGRAMMABLE_IRQ (1<<0)
+#define CANDEV_IO_RESERVED (1<<1)
enum timing_BTR1 {
MAX_TSEG1 = 15,
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
#include "./can.h"
+#include "./can_sysdep.h"
#include "./constants.h"
#include "./can_queue.h"
int canqueue_ends_init_chip(struct canque_ends_t *qends, struct chip_t *chip, struct msgobj_t *obj);
+int canqueue_ends_done_chip(struct canque_ends_t *qends);
--- /dev/null
+/* finish.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+void msgobj_done(struct msgobj_t *obj);
+void canchip_done(struct chip_t *chip);
+void candevice_done(struct candevice_t *candev);
+void canhardware_done(struct canhardware_t *candev);
* Version lincan-0.2 9 Jul 2003
*/
-#include <asm/io.h>
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
#include "./can.h"
#include "./constants.h"
+#include "./can_sysdep.h"
#include "./can_queue.h"
#ifdef CAN_DEBUG
#define CANMSG(fmt,args...) printk(KERN_ERR "can.o: " fmt,##args)
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7))
-
-#define MINOR_NR \
- (MINOR(file->f_dentry->d_inode->i_rdev))
-
-#else /* Linux kernel > 2.5.7 */
-
-#define MINOR_NR \
- (minor(file->f_dentry->d_inode->i_rdev))
-#endif /* Linux kernel > 2.5.7 */
-
-#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
- typedef void irqreturn_t;
- #define IRQ_NONE
- #define IRQ_HANDLED
- #define IRQ_RETVAL(x)
-#endif /* <=2.5.67 */
/**
* struct canhardware_t - structure representing pointers to all CAN boards
* @flags: chip flags: %CHIP_CONFIGURED .. chip is configured,
* %CHIP_SEGMENTED .. access to the chip is segmented (mainly for i82527 chips)
* @clock: chip base clock frequency in Hz
+ * @baudrate: selected chip baudrate in Hz
* @write_register: write chip register function copy -
* @read_register: read chip register function copy
* @sja_cdr_reg: SJA specific register -
int chip_irq;
unsigned long chip_base_addr;
unsigned int flags;
- int clock; /* Chip clock in Hz */
+ long clock; /* Chip clock in Hz */
+ long baudrate;
void (*write_register)(unsigned char data,unsigned long address);
unsigned (*read_register)(unsigned long address);
struct candevice_t *hostdevice;
- int max_objects; /* 1 for sja1000, 15 for */
+ int max_objects; /* 1 for sja1000, 15 for i82527 */
};
/**
* canque_test_outslot() call and is freed by canque_free_outslot()
* or rescheduled canque_again_outslot()
* @tx_retry_cnt: transmission attempt counter
+ * @tx_timeout: can be used by chip driver to check for the transmission timeout
* @rx_msg: temporary storage to hold received messages before
* calling to canque_filter_msg2edges()
* @hostchip: pointer to the &chip_t structure this object belongs to
struct canque_edge_t *tx_qedge;
struct canque_slot_t *tx_slot;
int tx_retry_cnt;
+ struct timer_list tx_timeout;
struct canmsg_t rx_msg;
struct mem_addr {
void *address;
struct mem_addr *next;
+ size_t size;
};
/* Structure for the RTR queue */
extern int major;
extern int minor[MAX_TOT_CHIPS];
extern int extended;
-extern int baudrate;
+extern int baudrate[MAX_TOT_CHIPS];
extern char *hw[MAX_HW_CARDS];
extern int irq[MAX_IRQ];
extern unsigned long io[MAX_HW_CARDS];
int init_hw_struct(void);
int list_hw(void);
-int add_mem_to_list(void *address_p);
-int del_mem_from_list(void *address_p);
-int del_mem_list(void);
+void *can_checked_malloc(size_t size);
+int can_checked_free(void *address_p);
+int can_del_mem_list(void);
endif
# Regular object files
O_OBJS += $(SUPPORTED_CARDS:%=%.o)
-O_OBJS += can_queue.o devcommon.o main.o modparms.o setup.o \
- sja1000p.o sja1000.o i82527.o irq.o boardlist.o \
+O_OBJS += can_queue.o can_quekern.o devcommon.o main.o modparms.o \
+ setup.o finish.o irq.o boardlist.o \
+ sja1000p.o sja1000.o i82527.o \
open.o proc.o close.o write.o read.o ioctl.o select.o
# Objects with exported symbols (-DEXPORT_SYMTAB)
OX_OBJS =
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/aim104.h"
#include "../include/sja1000.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/template.c
candev->nr_82527_chips=0;
candev->nr_sja1000_chips=1;
candev->nr_all_chips=1;
- candev->flags &= ~PROGRAMMABLE_IRQ;
+ candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
*
* The function template_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* possible to load the driver with the hardware option hw=bfadcan.
*/
-#define __NO_VERSION__ /* this is not a main module, do not include module info */
-
-#include <linux/autoconf.h>
-
-#include <linux/module.h>
-
-#include <linux/version.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
#define WINDOWED_ACCESS
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/i82527.h"
#include "../include/sja1000p.h"
+#define __NO_VERSION__
+#include <linux/module.h>
+
long clock_freq;
MODULE_PARM(clock_freq,"i");
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/bfadcan.c
candev->nr_82527_chips=NR_82527;
candev->nr_sja1000_chips=NR_SJA1000;
candev->nr_all_chips=NR_82527+NR_SJA1000;
- candev->flags |= 0 /* PROGRAMMABLE_IRQ */ ;
+ candev->flags |= 0 /* CANDEV_PROGRAMMABLE_IRQ */ ;
return 0;
}
*
* The function bfadcan_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
void bfadcan_write_register(unsigned char data, unsigned long address)
{
#ifdef WINDOWED_ACCESS
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&bfadcan_win_lock,flags);
outb(address&0x00ff,0x200);
outb(data, 0x201);
unsigned bfadcan_read_register(unsigned long address)
{
#ifdef WINDOWED_ACCESS
- long flags;
+ unsigned long flags;
int ret;
spin_lock_irqsave(&bfadcan_win_lock,flags);
outb(address&0x00ff,0x200);
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-#include <linux/version.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include ".supported_cards.h"
--- /dev/null
+/* can_quekern.c - CAN message queues functions for the Linux kernel
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/can_queue.h"
+
+//#define CAN_DEBUG
+
+extern atomic_t edge_num_cnt;
+
+#ifdef CAN_DEBUG
+ #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
+ ##args)
+
+#else
+ #define DEBUGQUE(fmt,args...)
+#endif
+
+#define ERRMSGQUE(fmt,args...) printk(KERN_ERR "can_queue: " fmt,\
+ ##args)
+
+
+/*
+ * Modifies Tx message processing
+ * 0 .. local message processing disabled
+ * 1 .. local messages disabled by default but can be enabled by canque_set_filt
+ * 2 .. local messages enabled by default, can be disabled by canque_set_filt
+ */
+extern int processlocal;
+
+void canque_dead_func(unsigned long data);
+
+/* Support for dead ends structures left after client close */
+spinlock_t canque_dead_func_lock;
+LIST_HEAD(canque_dead_ends);
+/* retrieved by list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers) */
+LIST_HEAD(canque_dead_edges);
+/* retrieved by list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers) */
+DECLARE_TASKLET(canque_dead_tl, canque_dead_func, 0);
+/* activated by tasklet_schedule(&canque_dead_tl) */
+
+
+static inline
+struct canque_edge_t *canque_dead_edges_cut_first(void)
+{
+ unsigned long flags;
+ struct canque_edge_t *edge;
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ if(list_empty(&canque_dead_edges))
+ edge=NULL;
+ else{
+ edge=list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers);
+ list_del(&edge->inpeers);
+ }
+ spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+ return edge;
+}
+
+void canque_dead_func(unsigned long data)
+{
+ unsigned long flags;
+ struct canque_edge_t *qedge;
+ struct canque_ends_t *qends;
+ struct list_head *entry;
+ int i;
+
+ while((qedge=canque_dead_edges_cut_first())){
+ DEBUGQUE("edge %d disposed\n",qedge->edge_num);
+ kfree(qedge);
+ }
+
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ entry=canque_dead_ends.next;
+ spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+ while(entry!=&canque_dead_ends){
+ qends=list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers);
+ entry=entry->next;
+ if(!list_empty(&qends->inlist))
+ continue;
+ if(!list_empty(&qends->idle))
+ continue;
+ for(i=CANQUEUE_PRIO_NR;i--;)
+ if(!list_empty(&qends->active[i]))
+ continue;
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ list_del(&qends->dead_peers);
+ spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+ DEBUGQUE("ends structure disposed\n");
+ kfree(qends);
+ }
+
+}
+
+
+void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
+{
+ unsigned long flags;
+
+ if(dead_fl) return;
+
+ if(canqueue_disconnect_edge(edge)<0){
+ ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n");
+ return;
+ }
+
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ list_add(&edge->inpeers,&canque_dead_edges);
+ spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+ tasklet_schedule(&canque_dead_tl);
+}
+
+
+
+/*if(qends->ends_flags & CAN_ENDSF_DEAD){
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ list_del(&qends->dead_peers);
+ list_add(&qends->dead_peers,&canque_dead_ends);
+ spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+ tasklet_schedule(&canque_dead_tl);
+}*/
+
+
+/**
+ * canqueue_notify_kern - notification callback handler for Linux userspace clients
+ * @qends: pointer to the callback side ends structure
+ * @qedge: edge which invoked notification
+ * @what: notification type
+ */
+void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
+{
+ DEBUGQUE("canqueue_notify_kern for edge %d, use %d and event %d\n",
+ qedge->edge_num,(int)atomic_read(&qedge->edge_used),what);
+ switch(what){
+ case CANQUEUE_NOTIFY_EMPTY:
+ wake_up(&qends->endinfo.fileinfo.emptyq);
+ if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
+ canque_edge_decref(qedge);
+ break;
+ case CANQUEUE_NOTIFY_SPACE:
+ wake_up(&qends->endinfo.fileinfo.writeq);
+ break;
+ case CANQUEUE_NOTIFY_PROC:
+ wake_up(&qends->endinfo.fileinfo.readq);
+ break;
+ case CANQUEUE_NOTIFY_NOUSR:
+ wake_up(&qends->endinfo.fileinfo.readq);
+ wake_up(&qends->endinfo.fileinfo.writeq);
+ wake_up(&qends->endinfo.fileinfo.emptyq);
+ break;
+ case CANQUEUE_NOTIFY_DEAD_WANTED:
+ case CANQUEUE_NOTIFY_DEAD:
+ if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+ canque_edge_decref(qedge);
+ break;
+ case CANQUEUE_NOTIFY_ATTACH:
+ break;
+ }
+}
+
+/**
+ * canqueue_ends_init_kern - Linux userspace clients specific ends initialization
+ * @qends: pointer to the callback side ends structure
+ */
+int canqueue_ends_init_kern(struct canque_ends_t *qends)
+{
+ canqueue_ends_init_gen(qends);
+ qends->context=NULL;
+ init_waitqueue_head(&qends->endinfo.fileinfo.readq);
+ init_waitqueue_head(&qends->endinfo.fileinfo.writeq);
+ init_waitqueue_head(&qends->endinfo.fileinfo.emptyq);
+ qends->notify=canqueue_notify_kern;
+ DEBUGQUE("canqueue_ends_init_kern\n");
+ return 0;
+}
+
+
+/**
+ * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to allocated slot
+ * @cmd: command type for slot
+ * @id: communication ID of message to send into edge
+ * @prio: optional priority of message
+ *
+ * Same as canque_get_inslot4id(), except, that it waits for free slot
+ * in case, that queue is full. Function is specific for Linux userspace clients.
+ * Return Value: If there is no usable edge negative value is returned.
+ */
+int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+ int cmd, unsigned long id, int prio)
+{
+ int ret=-1;
+ DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
+ wait_event_interruptible((qends->endinfo.fileinfo.writeq),
+ (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
+ return ret;
+}
+
+/**
+ * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to received slot
+ *
+ * The same as canque_test_outslot(), except it waits in the case, that there is
+ * no ready slot for given ends. Function is specific for Linux userspace clients.
+ * Return Value: Negative value informs, that there is no ready output
+ * slot for given ends. Positive value is equal to the command
+ * slot has been allocated by the input side.
+ */
+int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+{
+ int ret=-1;
+ DEBUGQUE("canque_get_outslot_wait_kern\n");
+ wait_event_interruptible((qends->endinfo.fileinfo.readq),
+ (ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
+ return ret;
+}
+
+/**
+ * canque_sync_wait_kern - wait for all slots processing
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Functions waits for ends transition into empty state.
+ * Return Value: Positive value indicates, that edge empty state has been reached.
+ * Negative or zero value informs about interrupted wait or other problem.
+ */
+int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+ int ret=-1;
+ DEBUGQUE("canque_sync_wait_kern\n");
+ wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
+ (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
+ return ret;
+}
+
+
+/**
+ * canque_new_edge_kern - allocate new edge structure in the Linux kernel context
+ * @slotsnr: required number of slots in the newly allocated edge structure
+ *
+ * Return Value: Returns pointer to allocated slot structure or %NULL if
+ * there is not enough memory to process operation.
+ */
+struct canque_edge_t *canque_new_edge_kern(int slotsnr)
+{
+ struct canque_edge_t *qedge;
+ qedge = (struct canque_edge_t *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL);
+ if(qedge == NULL) return NULL;
+
+ memset(qedge,0,sizeof(struct canque_edge_t));
+ spin_lock_init(&qedge->fifo.fifo_lock);
+ if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){
+ kfree(qedge);
+ DEBUGQUE("canque_new_edge_kern failed\n");
+ return NULL;
+ }
+ atomic_set(&qedge->edge_used,1);
+ qedge->filtid = 0;
+ qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
+ qedge->edge_prio = 0;
+ #ifdef CAN_DEBUG
+ /* not exactly clean, but enough for debugging */
+ atomic_inc(&edge_num_cnt);
+ qedge->edge_num=atomic_read(&edge_num_cnt);
+ #endif /* CAN_DEBUG */
+ DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num);
+ return qedge;
+}
+
+/**
+ * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Same as canqueue_disconnect_edge(), but tries to wait for state with zero
+ * use counter.
+ * Return Value: Negative value means, that edge is used and cannot
+ * be disconnected yet. Operation has to be delayed.
+ */
+int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+ canque_fifo_set_fl(&qedge->fifo,BLOCK);
+ DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
+ if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
+ canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
+
+ if(atomic_read(&qedge->edge_used)>0)
+ atomic_dec(&qedge->edge_used);
+
+ DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
+ wait_event((qends->endinfo.fileinfo.emptyq),
+ (canqueue_disconnect_edge(qedge)>=0));
+
+ /*set_current_state(TASK_UNINTERRUPTIBLE);*/
+ /*schedule_timeout(HZ);*/
+ return 0;
+ } else {
+ DEBUGQUE("canqueue_disconnect_edge_kern cannot set DEAD\n");
+ return -1;
+ }
+}
+
+
+int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list)
+{
+ struct canque_edge_t *edge;
+ unsigned long flags;
+ for(;;){
+ spin_lock_irqsave(&qends->ends_lock,flags);
+ if(list_empty(list)){
+ spin_unlock_irqrestore(&qends->ends_lock,flags);
+ return 0;
+ }
+ if(list == &qends->inlist)
+ edge=list_entry(list->next,struct canque_edge_t,inpeers);
+ else
+ edge=list_entry(list->next,struct canque_edge_t,outpeers);
+ atomic_inc(&edge->edge_used);
+ spin_unlock_irqrestore(&qends->ends_lock,flags);
+ if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
+ /* Free edge memory */
+ canque_fifo_done(&edge->fifo);
+ kfree(edge);
+ }else{
+ canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+ canque_edge_decref(edge);
+ DEBUGQUE("canqueue_disconnect_list_kern in troubles\n");
+ DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags);
+ return -1;
+ }
+ }
+}
+
+void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list)
+{
+ struct canque_edge_t *edge;
+ struct list_head *entry;
+
+ /* has to be called with qends->ends_lock already locked */
+ list_for_each(entry,&qends->inlist){
+ if(list == &qends->inlist)
+ edge=list_entry(list->next,struct canque_edge_t,inpeers);
+ else
+ edge=list_entry(list->next,struct canque_edge_t,outpeers);
+ canque_fifo_set_fl(&edge->fifo,BLOCK);
+ }
+}
+
+int canqueue_ends_sync_all_kern(struct canque_ends_t *qends)
+{
+ struct canque_edge_t *qedge;
+
+ canque_for_each_inedge(qends, qedge){
+ DEBUGQUE("canque_sync_wait_kern called for edge %d\n",qedge->edge_num);
+ canque_sync_wait_kern(qends, qedge);
+ }
+ return 0;
+}
+
+int canqueue_ends_done_inends(struct canque_ends_t *qends, int send_rest)
+{
+ struct canque_edge_t *edge;
+
+ canque_for_each_inedge(qends, edge){
+ canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+ if(send_rest){
+ canque_edge_incref(edge);
+ if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){
+ if(!canque_fifo_test_fl(&edge->fifo, EMPTY))
+ continue;
+ if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY))
+ continue;
+ }
+ canque_edge_decref(edge);
+ }
+ }
+ return list_empty(&qends->inlist)?0:1;
+}
+
+
+/**
+ * canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients
+ * @qends: pointer to ends structure
+ * @sync: flag indicating, that user wants to wait for processing of all remaining
+ * messages
+ *
+ * Return Value: Function should be designed such way to not fail.
+ */
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync)
+{
+ unsigned long flags;
+ int i;
+ int delayed;
+
+ DEBUGQUE("canqueue_ends_dispose_kern\n");
+ spin_lock_irqsave(&qends->ends_lock,flags);
+ canqueue_block_list(qends, &qends->idle);
+ for(i=CANQUEUE_PRIO_NR;--i>=0;){
+ canqueue_block_list(qends, &qends->active[i]);
+ }
+ canqueue_block_list(qends, &qends->idle);
+ canqueue_block_list(qends, &qends->inlist);
+ spin_unlock_irqrestore(&qends->ends_lock,flags);
+
+ /*Wait for sending of all pending messages in the output FIFOs*/
+ if(sync)
+ canqueue_ends_sync_all_kern(qends);
+
+ /* Finish all outgoing edges listed in inends */
+ delayed=canqueue_ends_done_inends(qends, 1);
+
+ delayed|=canqueue_disconnect_list_kern(qends, &qends->idle);
+ for(i=CANQUEUE_PRIO_NR;--i>=0;){
+ delayed|=canqueue_disconnect_list_kern(qends, &qends->active[i]);
+ }
+
+ wake_up(&qends->endinfo.fileinfo.readq);
+ wake_up(&qends->endinfo.fileinfo.writeq);
+ wake_up(&qends->endinfo.fileinfo.emptyq);
+
+ if(delayed){
+ spin_lock_irqsave(&canque_dead_func_lock, flags);
+ qends->ends_flags |= CAN_ENDSF_DEAD;
+ list_add(&qends->dead_peers,&canque_dead_ends);
+ spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+ tasklet_schedule(&canque_dead_tl);
+
+ DEBUGQUE("canqueue_ends_dispose_kern delayed\n");
+ return 1;
+ }
+
+ kfree(qends);
+ DEBUGQUE("canqueue_ends_dispose_kern finished\n");
+ return 0;
+}
+
+void canqueue_kern_initialize()
+{
+
+
+}
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/wait.h>
#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/can_queue.h"
/*
*/
extern int processlocal;
-/*#define CAN_DEBUG*/
+atomic_t edge_num_cnt;
+
+//#define CAN_DEBUG
#ifdef CAN_DEBUG
#define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
##args)
-
- atomic_t edge_num_cnt;
+
#else
#define DEBUGQUE(fmt,args...)
#endif
#define CANQUE_ROUNDROB 1
+
/**
* canque_fifo_flush_slots - free all ready slots from the FIFO
* @fifo: pointer to the FIFO structure
struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd)
{
int ret=-2;
- unsigned long flags;
struct canque_edge_t *edge;
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(!list_empty(&qends->inlist)){
- edge=list_entry(qends->inlist.next,struct canque_edge_t,inpeers);
- if(!canque_fifo_test_fl(&edge->fifo,BLOCK)&&!canque_fifo_test_fl(&edge->fifo,DEAD)){
- atomic_inc(&edge->edge_used);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
+ edge=canque_first_inedge(qends);
+ if(edge){
+ if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){
ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
if(ret>0){
*qedgep=edge;
return ret;
}
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&edge->edge_used))
- canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
}
+ canque_edge_decref(edge);
}
- spin_unlock_irqrestore(&qends->ends_lock, flags);
*qedgep=NULL;
DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd);
return ret;
int cmd, unsigned long id, int prio)
{
int ret=-2;
- unsigned long flags;
struct canque_edge_t *edge, *bestedge=NULL;
- struct list_head *entry;
- spin_lock_irqsave(&qends->ends_lock, flags);
- list_for_each(entry,&qends->inlist){
- edge=list_entry(entry,struct canque_edge_t,inpeers);
- if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD))
+ canque_for_each_inedge(qends, edge){
+ if(canque_fifo_test_fl(&edge->fifo,BLOCK))
continue;
if((id^edge->filtid)&edge->filtmask)
continue;
if (!edge->filtmask) continue;
} else {
if(edge->filtmask){
+ canque_edge_decref(bestedge);
bestedge=edge;
+ canque_edge_incref(bestedge);
continue;
}
}
} else {
if(bestedge->edge_prio<=prio) continue;
}
+ canque_edge_decref(bestedge);
}
bestedge=edge;
+ canque_edge_incref(bestedge);
}
if((edge=bestedge)!=NULL){
- atomic_inc(&edge->edge_used);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
if(ret>0){
*qedgep=edge;
DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num);
return ret;
}
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&edge->edge_used))
- canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+ canque_edge_decref(bestedge);
}
- spin_unlock_irqrestore(&qends->ends_lock, flags);
*qedgep=NULL;
DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio);
return ret;
struct canque_edge_t *qedge, struct canque_slot_t *slot)
{
int ret;
- unsigned long flags;
ret=canque_fifo_put_inslot(&qedge->fifo,slot);
if(ret) {
canque_activate_edge(qends,qedge);
canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC);
}
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&qedge->edge_used))
- canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
+ canque_edge_decref(qedge);
DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret);
return ret;
}
struct canque_edge_t *qedge, struct canque_slot_t *slot)
{
int ret;
- unsigned long flags;
ret=canque_fifo_abort_inslot(&qedge->fifo,slot);
if(ret) {
canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE);
}
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&qedge->edge_used))
- canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
+ canque_edge_decref(qedge);
DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret);
return ret;
}
{
int destnr=0;
int ret;
- unsigned long flags;
unsigned long msgid;
struct canque_edge_t *edge;
- struct list_head *entry;
struct canque_slot_t *slot;
DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
msg->id, msg->flags);
msgid = canque_filtid2internal(msg->id, msg->flags);
- spin_lock_irqsave(&qends->ends_lock, flags);
- list_for_each(entry,&qends->inlist){
- edge=list_entry(entry,struct canque_edge_t,inpeers);
- if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD))
+ canque_for_each_inedge(qends, edge) {
+ if(canque_fifo_test_fl(&edge->fifo,BLOCK))
continue;
- /* FIXME: the next comparison should be outside of ends lock */
if((msgid^edge->filtid)&edge->filtmask)
continue;
- atomic_inc(&edge->edge_used);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0);
if(ret>0){
slot->msg=*msg;
}
}
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&edge->edge_used))
- canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
}
- spin_unlock_irqrestore(&qends->ends_lock, flags);
DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr);
return destnr;
}
unsigned long flags;
int prio;
struct canque_edge_t *edge;
+ int ret;
spin_lock_irqsave(&qends->ends_lock, flags);
for(prio=CANQUEUE_PRIO_NR;--prio>=0;){
- if(!list_empty(&qends->active[prio])){
+ while(!list_empty(&qends->active[prio])){
edge=list_entry(qends->active[prio].next,struct canque_edge_t,outpeers);
- atomic_inc(&edge->edge_used);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
- *qedgep=edge;
- DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
- return canque_fifo_test_outslot(&edge->fifo, slotp);
+ if(!canque_fifo_test_fl(&edge->fifo,DEAD)) {
+ canque_edge_incref(edge);
+ spin_unlock_irqrestore(&qends->ends_lock, flags);
+ *qedgep=edge;
+ DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
+ ret=canque_fifo_test_outslot(&edge->fifo, slotp);
+ if(ret>=0)
+ return ret;
+ spin_lock_irqsave(&qends->ends_lock, flags);
+ }
+ spin_lock(&edge->fifo.fifo_lock);
+ if(canque_fifo_test_and_set_fl(&edge->fifo,INACTIVE)) {
+ list_del(&edge->outpeers);
+ list_add(&edge->outpeers,&qends->idle);
+ }
+ spin_unlock(&edge->fifo.fifo_lock);
}
}
spin_unlock_irqrestore(&qends->ends_lock, flags);
if(ret&CAN_FIFOF_FULL)
canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
spin_lock_irqsave(&qends->ends_lock, flags);
- if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB){
+ if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){
spin_lock(&qedge->fifo.fifo_lock);
if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
+ canque_fifo_set_fl(&qedge->fifo,INACTIVE);
list_del(&qedge->outpeers);
list_add(&qedge->outpeers,&qends->idle);
- }
- #if CANQUE_ROUNDROB
- else{
+ } else{
list_del(&qedge->outpeers);
list_add_tail(&qedge->outpeers,&qends->active[qedge->edge_prio]);
}
- #endif /*CANQUE_ROUNDROB*/
spin_unlock(&qedge->fifo.fifo_lock);
}
- if(atomic_dec_and_test(&qedge->edge_used))
- canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
spin_unlock_irqrestore(&qends->ends_lock, flags);
+ canque_edge_decref(qedge);
DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret);
return ret;
}
struct canque_edge_t *qedge, struct canque_slot_t *slot)
{
int ret;
- unsigned long flags;
ret=canque_fifo_again_outslot(&qedge->fifo, slot);
- spin_lock_irqsave(&qends->ends_lock, flags);
- if(atomic_dec_and_test(&qedge->edge_used))
- canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
- spin_unlock_irqrestore(&qends->ends_lock, flags);
+ canque_edge_decref(qedge);
DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret);
return ret;
}
canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH);
}
spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
- if(!ret)canque_fifo_clear_fl(&qedge->fifo,BLOCK);
+ if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK);
spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
}
-/**
- * canqueue_notify_kern - notification callback handler for Linux userspace clients
- * @qends: pointer to the callback side ends structure
- * @qedge: edge which invoked notification
- * @what: notification type
- */
-void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
-{
- DEBUGQUE("canqueue_notify_kern for edge %d and event %d\n",qedge->edge_num,what);
- switch(what){
- case CANQUEUE_NOTIFY_EMPTY:
- wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
- break;
- case CANQUEUE_NOTIFY_SPACE:
- wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
- break;
- case CANQUEUE_NOTIFY_PROC:
- wake_up_interruptible(&qends->endinfo.fileinfo.readq);
- break;
- case CANQUEUE_NOTIFY_NOUSR:
- wake_up_interruptible(&qends->endinfo.fileinfo.readq);
- wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
- wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
- break;
- case CANQUEUE_NOTIFY_DEAD:
- if(atomic_read(&qedge->edge_used)>0)
- atomic_dec(&qedge->edge_used);
- break;
- case CANQUEUE_NOTIFY_ATACH:
- atomic_inc(&qedge->edge_used);
- break;
- }
-}
-
-/**
- * canqueue_ends_init_kern - Linux userspace clients specific ends initialization
- * @qends: pointer to the callback side ends structure
- */
-int canqueue_ends_init_kern(struct canque_ends_t *qends)
-{
- canqueue_ends_init_gen(qends);
- qends->context=NULL;
- init_waitqueue_head(&qends->endinfo.fileinfo.readq);
- init_waitqueue_head(&qends->endinfo.fileinfo.writeq);
- init_waitqueue_head(&qends->endinfo.fileinfo.emptyq);
- qends->notify=canqueue_notify_kern;
- DEBUGQUE("canqueue_ends_init_kern\n");
- return 0;
-}
-
-
-/**
- * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID
- * @qends: ends structure belonging to calling communication object
- * @qedgep: place to store pointer to found edge
- * @slotp: place to store pointer to allocated slot
- * @cmd: command type for slot
- * @id: communication ID of message to send into edge
- * @prio: optional priority of message
- *
- * Same as canque_get_inslot4id(), except, that it waits for free slot
- * in case, that queue is full. Function is specific for Linux userspace clients.
- * Return Value: If there is no usable edge negative value is returned.
- */
-int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
- struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
- int cmd, unsigned long id, int prio)
-{
- int ret=-1;
- DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
- wait_event_interruptible((qends->endinfo.fileinfo.writeq),
- (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
- return ret;
-}
-
-/**
- * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends
- * @qends: ends structure belonging to calling communication object
- * @qedgep: place to store pointer to found edge
- * @slotp: place to store pointer to received slot
- *
- * The same as canque_test_outslot(), except it waits in the case, that there is
- * no ready slot for given ends. Function is specific for Linux userspace clients.
- * Return Value: Negative value informs, that there is no ready output
- * slot for given ends. Positive value is equal to the command
- * slot has been allocated by the input side.
- */
-int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
- struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
-{
- int ret=-1;
- DEBUGQUE("canque_get_outslot_wait_kern\n");
- wait_event_interruptible((qends->endinfo.fileinfo.readq),
- (ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
- return ret;
-}
-
-/**
- * canque_sync_wait_kern - wait for all slots processing
- * @qends: ends structure belonging to calling communication object
- * @qedge: pointer to edge
- *
- * Functions waits for ends transition into empty state.
- * Return Value: Positive value indicates, that edge empty state has been reached.
- * Negative or zero value informs about interrupted wait or other problem.
- */
-int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
-{
- int ret=-1;
- DEBUGQUE("canque_sync_wait_kern\n");
- wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
- (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
- return ret;
-}
-
-
-/**
- * canque_new_edge_kern - allocate new edge structure in the Linux kernel context
- * @slotsnr: required number of slots in the newly allocated edge structure
- *
- * Return Value: Returns pointer to allocated slot structure or %NULL if
- * there is not enough memory to process operation.
- */
-struct canque_edge_t *canque_new_edge_kern(int slotsnr)
-{
- struct canque_edge_t *qedge;
- qedge = (struct canque_edge_t *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL);
- if(qedge == NULL) return NULL;
-
- memset(qedge,0,sizeof(struct canque_edge_t));
- spin_lock_init(&qedge->fifo.fifo_lock);
- if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){
- kfree(qedge);
- DEBUGQUE("canque_new_edge_kern failed\n");
- return NULL;
- }
- atomic_set(&qedge->edge_used,0);
- qedge->filtid = 0;
- qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
- qedge->edge_prio = 0;
- #ifdef CAN_DEBUG
- /* not exactly clean, but enough for debugging */
- atomic_inc(&edge_num_cnt);
- qedge->edge_num=atomic_read(&edge_num_cnt);
- #endif /* CAN_DEBUG */
- DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num);
- return qedge;
-}
-
/**
* canqueue_connect_edge - connect edge between two communication entities
* @qedge: pointer to edge
unsigned long flags;
if(qedge == NULL) return -1;
DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num);
- atomic_inc(&qedge->edge_used);
+ canque_edge_incref(qedge);
spin_lock_irqsave(&inends->ends_lock, flags);
spin_lock(&outends->ends_lock);
spin_lock(&qedge->fifo.fifo_lock);
spin_unlock(&qedge->fifo.fifo_lock);
spin_unlock(&outends->ends_lock);
spin_unlock_irqrestore(&inends->ends_lock, flags);
- canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATACH);
-
- spin_lock_irqsave(&qedge->fifo.fifo_lock, flags);
- if(atomic_dec_and_test(&qedge->edge_used))
- canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
- spin_unlock_irqrestore(&qedge->fifo.fifo_lock, flags);
+ canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH);
+
+ if(canque_fifo_test_and_set_fl(&qedge->fifo, READY))
+ canque_edge_decref(qedge);
return 0;
}
* canqueue_disconnect_edge - disconnect edge from communicating entities
* @qedge: pointer to edge
*
- * Return Value: Negative value means, that edge is used and cannot
- * be disconnected. Operation has to be delayed.
+ * Return Value: Negative value means, that edge is used by somebody
+ * other and cannot be disconnected. Operation has to be delayed.
*/
int canqueue_disconnect_edge(struct canque_edge_t *qedge)
{
return ret;
}
-/**
- * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
- * @qends: ends structure belonging to calling communication object
- * @qedge: pointer to edge
- *
- * Same as canqueue_disconnect_edge(), but tries to wait for state with zero
- * use counter.
- * Return Value: Negative value means, that edge is used and cannot
- * be disconnected yet. Operation has to be delayed.
- */
-int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
-{
- canque_fifo_set_fl(&qedge->fifo,BLOCK);
- DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
- if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
- canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
- if(atomic_read(&qedge->edge_used)>0)
- atomic_dec(&qedge->edge_used);
- DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
- wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
- (canqueue_disconnect_edge(qedge)>=0));
- return 0;
- } else {
- DEBUGQUE("canqueue_disconnect_edge_kern failed\n");
- return -1;
- }
-}
-
-
-int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list)
-{
- struct canque_edge_t *edge;
- unsigned long flags;
- for(;;){
- spin_lock_irqsave(&qends->ends_lock,flags);
- if(list_empty(list)){
- spin_unlock_irqrestore(&qends->ends_lock,flags);
- return 0;
- }
- if(list == &qends->inlist)
- edge=list_entry(list->next,struct canque_edge_t,inpeers);
- else
- edge=list_entry(list->next,struct canque_edge_t,outpeers);
- atomic_inc(&edge->edge_used);
- spin_unlock_irqrestore(&qends->ends_lock,flags);
- if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
- /* Free edge memory */
- canque_fifo_done(&edge->fifo);
- kfree(edge);
- }else{
- DEBUGQUE("canqueue_disconnect_list_kern in troubles\n");
- DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags);
- return -1;
- }
- }
-}
-
-void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list)
-{
- struct canque_edge_t *edge;
- struct list_head *entry;
-
- /* has to be called with qends->ends_lock already locked */
- list_for_each(entry,&qends->inlist){
- if(list == &qends->inlist)
- edge=list_entry(list->next,struct canque_edge_t,inpeers);
- else
- edge=list_entry(list->next,struct canque_edge_t,outpeers);
- canque_fifo_set_fl(&edge->fifo,BLOCK);
- }
-}
-
-
-/**
- * canqueue_ends_done_kern - finalizing of the ends structure for Linux kernel clients
- * @qends: pointer to ends structure
- * @sync: flag indicating, that user wants to wait for processing of all remaining
- * messages
- *
- * Return Value: Function should be designed such way to not fail.
- */
-int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync)
-{
- unsigned long flags;
- int i;
-
- DEBUGQUE("canqueue_ends_done_kern\n");
- spin_lock_irqsave(&qends->ends_lock,flags);
- canqueue_block_list(qends, &qends->idle);
- for(i=CANQUEUE_PRIO_NR;--i>=0;){
- canqueue_block_list(qends, &qends->active[i]);
- }
- canqueue_block_list(qends, &qends->idle);
- canqueue_block_list(qends, &qends->inlist);
- spin_unlock_irqrestore(&qends->ends_lock,flags);
-
- for(i=CANQUEUE_PRIO_NR;--i>=0;){
- canqueue_disconnect_list_kern(qends, &qends->active[i]);
- }
- canqueue_disconnect_list_kern(qends, &qends->idle);
- canqueue_disconnect_list_kern(qends, &qends->inlist);
-
- wake_up_interruptible(&qends->endinfo.fileinfo.readq);
- wake_up_interruptible(&qends->endinfo.fileinfo.writeq);
- wake_up_interruptible(&qends->endinfo.fileinfo.emptyq);
-
-
- return 0;
-}
-
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/cc_can104.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/template.c
candev->nr_82527_chips=0;
candev->nr_sja1000_chips=1;
candev->nr_all_chips=1;
- candev->flags &= ~PROGRAMMABLE_IRQ;
+ candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
*
* The function template_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/close.h"
#include "../include/i82527.h"
#include "../include/setup.h"
+#define __NO_VERSION__
+#include <linux/module.h>
+
int can_close(struct inode *inode, struct file *file)
{
struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
qends = canuser->qends;
list_del(&canuser->peers);
- canqueue_ends_done_kern(qends, 1);
canuser->qends = NULL;
- kfree(qends);
+ canqueue_ends_dispose_kern(qends, file->f_flags & O_SYNC);
kfree(canuser);
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/wait.h>
#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/can_queue.h"
#include "../include/main.h"
#include "../include/devcommon.h"
/*case CANQUEUE_NOTIFY_EMPTY:*/
/*case CANQUEUE_NOTIFY_SPACE:*/
/*case CANQUEUE_NOTIFY_NOUSR:
- wake_up_interruptible(&qends->endinfo.chipinfo.daemonq);
+ wake_up(&qends->endinfo.chipinfo.daemonq);
break;*/
case CANQUEUE_NOTIFY_PROC:
- /*wake_up_interruptible(&qends->endinfo.chipinfo.daemonq);*/
+ /*wake_up(&qends->endinfo.chipinfo.daemonq);*/
chip->chipspecops->wakeup_tx(chip, obj);
break;
+ case CANQUEUE_NOTIFY_DEAD_WANTED:
case CANQUEUE_NOTIFY_DEAD:
- if(atomic_read(&qedge->edge_used)>0)
- atomic_dec(&qedge->edge_used);
+ if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+ canque_edge_decref(qedge);
break;
- case CANQUEUE_NOTIFY_ATACH:
- atomic_inc(&qedge->edge_used);
+ case CANQUEUE_NOTIFY_ATTACH:
break;
}
}
}
+int canqueue_ends_done_chip(struct canque_ends_t *qends)
+{
+ return 0;
+}
--- /dev/null
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/devcommon.h"
+#include "../include/finish.h"
+#include "../include/setup.h"
+
+
+
+void msgobj_done(struct msgobj_t *obj)
+{
+ if(obj->qends) {
+ if(canqueue_ends_done_chip(obj->qends) < 0)
+ CANMSG("msgobj_done: problem with chip queue ends\n");
+ }
+
+ if((obj->hostchip) && (obj->object>0)) {
+ if(obj->hostchip->msgobj[obj->object-1] == obj)
+ obj->hostchip->msgobj[obj->object-1]=NULL;
+ else
+ CANMSG("msgobj_done: not registered in the chip_t\n");
+ obj->hostchip=NULL;
+ }
+
+ if((obj->minor>=0)) {
+ if(objects_p[obj->minor] == obj)
+ objects_p[obj->minor] = NULL;
+ else
+ CANMSG("msgobj_done: not registered as minor\n");
+ }
+
+ del_timer_sync(&obj->tx_timeout);
+
+ if(obj->qends) {
+ can_checked_free(obj->qends);
+ }
+ obj->qends=NULL;
+}
+
+
+void canchip_done(struct chip_t *chip)
+{
+
+ int i;
+ struct msgobj_t *obj;
+
+ if((chip->hostdevice) && (chip->chip_idx>=0)) {
+ if(chip->hostdevice->chip[chip->chip_idx] == chip)
+ chip->hostdevice->chip[chip->chip_idx] = NULL;
+ else
+ CANMSG("canchip_done: not registered in hostdevice\n");
+ }
+
+ if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+ free_irq(chip->chip_irq, chip);
+ chip->flags &= ~CHIP_IRQ_SETUP;
+ }
+
+ can_synchronize_irq(chip->chip_irq);
+
+ for(i=0; i<chip->max_objects; i++){
+ if((obj=chip->msgobj[i])==NULL)
+ continue;
+ msgobj_done(obj);
+ can_checked_free(obj);
+ }
+
+ can_checked_free(chip->chipspecops);
+ chip->chipspecops=NULL;
+
+}
+
+void candevice_done(struct candevice_t *candev)
+{
+ int i;
+ struct chip_t *chip;
+
+ for(i=0; i<candev->nr_all_chips; i++){
+ if((chip=candev->chip[i])==NULL)
+ continue;
+ canchip_done(chip);
+ can_checked_free(chip);
+
+ }
+ if(candev->flags & CANDEV_IO_RESERVED) {
+ candev->hwspecops->release_io(candev);
+ candev->flags &= ~CANDEV_IO_RESERVED;
+ }
+ can_checked_free(candev->hwspecops);
+ candev->hwspecops=NULL;
+}
+
+void canhardware_done(struct canhardware_t *canhw)
+{
+ int i;
+ struct candevice_t *candev;
+
+ for(i=0; i<canhw->nr_boards; i++){
+ if((candev=canhw->candevice[i])==NULL)
+ continue;
+ candevice_done(candev);
+ can_checked_free(candev);
+ }
+
+}
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/i82527.h"
else
DEBUGMSG("Could read back, hardware is probably configured correctly\n");
- if (baudrate == 0)
- baudrate=1000;
+ if (chip->baudrate == 0)
+ chip->baudrate=1000000;
- if (i82527_baud_rate(chip,baudrate*1000,chip->clock,0,75,0)) {
+ if (i82527_baud_rate(chip,chip->baudrate,chip->clock,0,75,0)) {
CANMSG("Error configuring baud rate\n");
return -ENODEV;
}
spin_unlock(&hardware_p->rtr_lock);
if (waitqueue_active(&rtr_search->rtr_wq))
- wake_up_interruptible(&rtr_search->rtr_wq);
+ wake_up(&rtr_search->rtr_wq);
}
int i82527_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/ioctl.h"
#include "../include/i82527.h"
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/irq.h"
*
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/m437.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/m437.c
candev->nr_82527_chips=1;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=1;
- candev->flags &= ~PROGRAMMABLE_IRQ;
+ candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
/* The M437 has no programmable IRQ */
return 0;
*
* The function m437_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
#include <linux/wrapper.h>
#endif
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-#include <asm/spinlock.h>
-#else
-#include <linux/spinlock.h>
-#endif
-
#if !defined (__GENKSYMS__)
#if (defined (MODVERSIONS) && !defined(NOVER))
#include <linux/modversions.h>
#include <linux/miscdevice.h>
#endif
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/modparms.h"
#include "../include/devcommon.h"
#include "../include/irq.h"
#include "../include/ioctl.h"
#include "../include/write.h"
+#include "../include/finish.h"
#define EXPORT_SYMTAB
MODULE_PARM(extended,"1i");
int pelican=0;
MODULE_PARM(pelican,"1i");
-int baudrate=0;
-MODULE_PARM(baudrate,"1i");
+int baudrate[MAX_TOT_CHIPS];
+MODULE_PARM(baudrate, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i");
char *hw[MAX_HW_CARDS]={NULL,};
MODULE_PARM(hw, "1-" __MODULE_STRING(MAX_HW_CARDS)"s");
int irq[MAX_IRQ]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int init_module(void)
{
- int res=0,i=0;
+ int res=0,i=0, j;
struct candevice_t *candev;
+ struct chip_t *chip;
if (parse_mod_parms())
return -EINVAL;
+ canqueue_kern_initialize();
+
if (init_hw_struct())
return -ENODEV;
candev=hardware_p->candevice[i];
if (candev->hwspecops->request_io(candev))
goto memory_error;
+ candev->flags|=CANDEV_IO_RESERVED;
}
for (i=0; i<hardware_p->nr_boards; i++) {
spin_lock_init(&hardware_p->rtr_lock);
hardware_p->rtr_queue=NULL;
- i=0;
- while ( (chips_p[i] != NULL) && (i < MAX_TOT_CHIPS) ) {
- if (chips_p[i]->chipspecops->irq_handler) {
- if (request_irq(chips_p[i]->chip_irq,chips_p[i]->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chips_p[i]))
- goto interrupt_error;
- else
- DEBUGMSG("Registered interrupt %d\n",chips_p[i]->chip_irq);
- }
- i++;
- }
-
for (i=0; i<hardware_p->nr_boards; i++) {
candev=hardware_p->candevice[i];
- if (candev->flags & PROGRAMMABLE_IRQ)
+ for(j=0; j<candev->nr_all_chips; j++) {
+ if((chip=candev->chip[j])==NULL)
+ continue;
+ if(!chip->chipspecops->irq_handler)
+ continue;
+
+ if (request_irq(chip->chip_irq,chip->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chip))
+ goto interrupt_error;
+ else {
+ DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
+ chip->flags |= CHIP_IRQ_SETUP;
+ }
+ }
+
+ if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
if (candev->hwspecops->program_irq(candev))
goto interrupt_error;
}
goto memory_error;
memory_error: ;
- for (i=0; i<hardware_p->nr_boards; i++) {
- candev=hardware_p->candevice[i];
- candev->hwspecops->release_io(candev);
- }
- goto register_error;
+ canhardware_done(hardware_p);
- register_error: ;
res=unregister_chrdev(major,DEVICE_NAME);
if (res<0)
CANMSG("Error unloading CAN driver, error: %d\n",res);
else
- CANMSG("Successfully unloaded CAN driver.\n");
+ CANMSG("No CAN devices or driver setup error.\n");
return -ENODEV;
}
void cleanup_module(void)
{
int res=0,i=0;
- struct candevice_t *candev;
#ifdef CONFIG_PROC_FS
if (can_delete_procdir())
#endif
}
#endif
- i=0;
- while ( (chips_p[i] != NULL) & (i < MAX_TOT_CHIPS) ) {
- if(chips_p[i]->chipspecops->irq_handler)
- free_irq(chips_p[i]->chip_irq, chips_p[i]);
- i++;
- }
- for (i=0; i<hardware_p->nr_boards; i++){
- candev=hardware_p->candevice[i];
- candev->hwspecops->release_io(candev);
- }
+ canhardware_done(hardware_p);
- if ( del_mem_list() )
+ if ( can_del_mem_list() )
CANMSG("Error deallocating memory\n");
res=unregister_chrdev(major,DEVICE_NAME);
*/
-#include <linux/autoconf.h>
-
-#include <linux/string.h>
-#include <linux/fs.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/modparms.h"
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/nsi.h"
#include "../include/i82527.h"
* RESET_ADDR represents the io-address of the hardware reset register.
* NR_82527 represents the number of intel 82527 chips on the board.
* NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
*/
#define RESET_ADDR 0x02
candev->nr_82527_chips=1;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=1;
- candev->flags |= PROGRAMMABLE_IRQ;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
/* The function template_program_irq is used for hardware that uses programmable
* interrupts. If your hardware doesn't use programmable interrupts you should
- * not set the candevices_t->flags entry to PROGRAMMABLE_IRQ and leave this
+ * not set the candevices_t->flags entry to CANDEV_PROGRAMMABLE_IRQ and leave this
* function unedited. Again this function is hardware specific so there's no
* example code.
*/
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/fs.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/open.h"
#include "../include/i82527.h"
#include "../include/setup.h"
+#define __NO_VERSION__
+#include <linux/module.h>
+
int can_open(struct inode *inode, struct file *file)
{
struct msgobj_t *obj;
struct chip_t *chip;
struct canuser_t *canuser;
struct canque_ends_t *qends;
+ struct canque_edge_t *edge;
if ( ((obj=objects_p[MINOR_NR]) == NULL) ||
((chip=objects_p[MINOR_NR]->hostchip) == NULL) ) {
list_add(&canuser->peers, &obj->obj_users);
- if(canqueue_connect_edge(canque_new_edge_kern(MAX_BUF_LENGTH),
- canuser->qends, obj->qends)<0) goto no_qedge;
+ if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
+ canuser->qends, obj->qends)<0) goto no_tx_qedge;
if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH),
- obj->qends, canuser->qends)<0) goto no_qedge;
+ obj->qends, canuser->qends)<0) goto no_rx_qedge;
+ /*FIXME: more generic model should be used there*/
+ canque_edge_decref(canuser->rx_edge0);
+ canque_edge_decref(edge);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
MOD_INC_USE_COUNT;
return 0;
- no_qedge:
+ no_rx_qedge:
+ canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+ canque_edge_decref(edge);
+ no_tx_qedge:
list_del(&canuser->peers);
- canqueue_ends_done_kern(qends, 1);
canuser->qends = NULL;
- kfree(qends);
- obj->qends = NULL;
+ canqueue_ends_dispose_kern(qends, 1);
no_qends:
kfree(canuser);
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pc-i03.h"
#include "../include/sja1000.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/pc-i03.c
*
* The function pci03_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pccan.h"
#include "../include/i82527.h"
int pccan_init_hw_data(struct candevice_t *candev)
{
candev->res_addr=candev->io_addr+0x6001;
- candev->flags |= PROGRAMMABLE_IRQ;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
if (!strcmp(candev->hwname,"pccan-q")) {
candev->nr_82527_chips=2;
* You can probably find more information at http://www.gespac.com
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pcccan.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/pcccan.c
candev->nr_82527_chips=NR_82527;
candev->nr_sja1000_chips=NR_SJA1000;
candev->nr_all_chips=NR_82527+NR_SJA1000;
- candev->flags &= ~PROGRAMMABLE_IRQ;
+ candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
*
* The function pcccan_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pcm3680.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/template.c
candev->nr_82527_chips=NR_82527;
candev->nr_sja1000_chips=NR_SJA1000;
candev->nr_all_chips=NR_82527+NR_SJA1000;
- candev->flags &= ~PROGRAMMABLE_IRQ;
+ candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
*
* The function template_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pikronisa.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of intel 82527 chips on the board.
* %NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/pikronisa.c
candev->nr_82527_chips=0;
candev->nr_sja1000_chips=1;
candev->nr_all_chips=1;
- candev->flags |= PROGRAMMABLE_IRQ*0;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
return 0;
}
*
* The function pikronisa_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/pip.h"
#include "../include/i82527.h"
candev->nr_82527_chips=1;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=1;
- candev->flags |= PROGRAMMABLE_IRQ;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#include <linux/kernel.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/proc_fs.h>
-#include <linux/version.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/proc.h"
#include "../include/setup.h"
+#define __NO_VERSION__
+#include <linux/module.h>
+
int add_channel_to_procdir(struct candevice_t *candev);
int remove_channel_from_procdir(void);
int add_object_to_procdir(int chip_nr);
{
struct proc_dir_entry *new_entry = NULL;
- new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct
- proc_dir_entry), GFP_KERNEL);
+ new_entry = (struct proc_dir_entry *)
+ can_checked_malloc(sizeof(struct proc_dir_entry));
if (new_entry == NULL)
return NULL;
{
if (del != NULL) {
proc_unregister(parent, del->low_ino);
- kfree(del);
- del = NULL;
+ can_checked_free(del);
return 0;
}
else return -ENODEV;
for (i=0; i < candev->nr_all_chips; i++) {
base->channel[cc] = (struct channelproc_t *)
- kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
+ can_checked_malloc(sizeof(struct channelproc_t));
if (base->channel[cc] == NULL)
return -ENOMEM;
- else if (add_mem_to_list(base->channel[cc]))
- return -ENOMEM;
sprintf(base->channel[cc]->ch_name, "channel%d",cc);
for (i=0; i<max_objects; i++) {
base->channel[chip_nr]->object[i] = (struct objectproc_t *)
- kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
-
-
+ can_checked_malloc(sizeof(struct objectproc_t));
+
if (base->channel[chip_nr]->object[i] == NULL)
return -ENOMEM;
- else if (add_mem_to_list( base->channel[chip_nr]->object[i]))
- return -ENOMEM;
sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/version.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/read.h"
#include "../include/ioctl.h"
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
-#include <linux/version.h>
#include <linux/poll.h>
-
-#include "../include/main.h"
#include "../include/select.h"
unsigned int can_poll(struct file *file, poll_table *wait)
* Version lincan-0.2 9 Jul 2003
*/
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/autoconf.h>
-
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/fs.h>
-#include <linux/ioport.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/devcommon.h"
#include "../include/setup.h"
+#include "../include/finish.h"
extern int sja1000_register(struct chipspecops_t *chipspecops);
extern int sja1000p_register(struct chipspecops_t *chipspecops);
int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase);
int init_chipspecops(struct candevice_t *candev, int chipnr);
-int add_mem_to_list(void *address_p)
+void *can_checked_malloc(size_t size)
{
struct mem_addr *mem_new;
+ void *address_p;
+
+ address_p=kmalloc(size,GFP_KERNEL);
+ if(address_p == NULL) {
+ CANMSG("can_checked_malloc: out of the memory\n");
+ return NULL;
+ }
#ifdef DEBUG_MEM
- DEBUGMSG("add_mem_to_list %p, mem_head=%p\n",address_p, mem_head);
- return 0;
+ DEBUGMSG("can_checked_malloc: allocated %d bytes at %p, mem_head=%p\n",
+ (int)size, address_p, mem_head);
#endif
mem_new=(struct mem_addr *)kmalloc(sizeof(struct mem_addr),GFP_KERNEL);
if (mem_new == NULL) {
- CANMSG("Memory list error.\n");
- return -ENOMEM;
+ CANMSG("can_checked_malloc: memory list allocation error.\n");
+ kfree(address_p);
+ return NULL;
}
mem_new->next=mem_head;
mem_new->address=address_p;
+ mem_new->size=size;
mem_head=mem_new;
- return 0;
+ return address_p;
}
-int del_mem_from_list(void *address_p)
+int can_checked_free(void *address_p)
{
- struct mem_addr *mem_search=NULL;
- struct mem_addr *mem_delete=NULL;
+ struct mem_addr **mem_pptr;
+ struct mem_addr *mem_del=NULL;
#ifdef DEBUG_MEM
- DEBUGMSG("del_mem_from_list %p, mem_head=%p\n", address_p, mem_head);
- return 0;
+ DEBUGMSG("can_checked_free %p, mem_head=%p\n", address_p, mem_head);
#endif
- if(mem_head == NULL) {
- CANMSG("del_mem_from_list: mem_head == NULL address_p=%p!\n",
- address_p);
- return 0;
- }
-
- mem_search = mem_head;
- if (mem_head->address == address_p) {
- kfree(mem_head->address);
- mem_head=mem_head->next;
- kfree(mem_search);
- }
- else {
- while (mem_search->next->address != address_p)
- mem_search=mem_search->next;
- kfree(mem_search->next->address);
- mem_delete=mem_search->next;
- mem_search->next=mem_search->next->next;
- kfree(mem_delete);
+ for(mem_pptr = &mem_head; (mem_del = *mem_pptr); mem_pptr = &mem_del->next) {
+ if (mem_del->address != address_p)
+ continue;
+ *mem_pptr=mem_del->next;
+ kfree(mem_del);
+ kfree(address_p);
+ return 0;
}
- return 0;
+
+ CANMSG("can_checked_free: address %p not found on the mem list\n", address_p);
+
+ kfree(address_p);
+ return -1;
}
-int del_mem_list(void)
+int can_del_mem_list(void)
{
- struct mem_addr *mem_old;
+ struct mem_addr *mem;
#ifdef DEBUG_MEM
- DEBUGMSG("del_mem_list, mem_head=%p\n", mem_head);
- return 0;
+ DEBUGMSG("can_del_mem_list, mem_head=%p\n", mem_head);
#endif
if(mem_head == NULL) {
- CANMSG("del_mem_list: mem_head == NULL!\n");
+ CANMSG("can_del_mem_list: no entries on the list - OK\n");
return 0;
}
- while (mem_head->next != NULL) {
- mem_old=mem_head;
- kfree(mem_old->address);
- mem_head=mem_old->next;
- kfree(mem_old);
+ while((mem=mem_head) != NULL) {
+ mem_head=mem->next;
+ CANMSG("can_del_mem_list: deleting %p with size %d\n",
+ mem->address, (int)mem->size);
+ kfree(mem->address);
+ kfree(mem);
}
return 0;
int init_device_struct(int card)
{
struct candevice_t *candev;
+ int ret;
- candev=(struct candevice_t *)kmalloc(sizeof(struct candevice_t),GFP_KERNEL);
+ candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t));
if (candev==NULL)
return -ENOMEM;
- else
- if ( add_mem_to_list(candev) )
- return -ENOMEM;
memset(candev, 0, sizeof(struct candevice_t));
candev->io_addr=io[card];
candev->dev_base_addr=io[card];
- candev->hwspecops=(struct hwspecops_t *)kmalloc(sizeof(struct hwspecops_t),GFP_KERNEL);
+ candev->hwspecops=(struct hwspecops_t *)can_checked_malloc(sizeof(struct hwspecops_t));
if (candev->hwspecops==NULL)
- return -ENOMEM;
- else
- if ( add_mem_to_list(candev->hwspecops) )
- return -ENOMEM;
+ goto error_nomem;
+
memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
if (init_hwspecops(candev))
- return -ENODEV;
+ goto error_nodev;
if (candev->hwspecops->init_hw_data(candev))
- return -ENODEV;
+ goto error_nodev;
if (init_chip_struct(candev))
- return -ENODEV;
+ goto error_nodev;
return 0;
+
+ error_nodev:
+ candevice_done(candev);
+ ret=-ENODEV;
+ goto error_both;
+
+ error_nomem:
+ ret=-ENOMEM;
+
+ error_both:
+ hardware_p->candevice[card]=NULL;
+ can_checked_free(candev);
+ return ret;
+
}
/* The function init_chip_struct is used to initialize all chip_t structures
/* Alocate and initialize the chip structures */
for (i=0; i < candev->nr_all_chips; i++) {
- candev->chip[i]=(struct chip_t *)kmalloc(sizeof(struct chip_t),GFP_KERNEL);
+ candev->chip[i]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t));
if (candev->chip[i]==NULL)
return -ENOMEM;
- else
- if ( add_mem_to_list(candev->chip[i]) )
- return -ENOMEM;
memset(candev->chip[i], 0, sizeof(struct chip_t));
candev->chip[i]->write_register=candev->hwspecops->write_register;
candev->chip[i]->read_register=candev->hwspecops->read_register;
- candev->chip[i]->chipspecops=(struct chipspecops_t *)kmalloc(sizeof(struct chipspecops_t),GFP_KERNEL);
+ candev->chip[i]->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
if (candev->chip[i]->chipspecops==NULL)
return -ENOMEM;
- else
- if ( add_mem_to_list(candev->chip[i]->chipspecops) )
- return -ENOMEM;
- chips_p[irq_count]=candev->chip[i];
+ chips_p[irq_count]=candev->chip[i];
candev->chip[i]->chip_idx=i;
candev->chip[i]->hostdevice=candev;
candev->chip[i]->chip_irq=irq[irq_count];
+ candev->chip[i]->baudrate=baudrate[irq_count]*1000;
+ if(!candev->chip[i]->baudrate)
+ candev->chip[i]->baudrate=baudrate[0]*1000;
candev->chip[i]->flags=0x0;
candev->hwspecops->init_chip_data(candev,i);
max_objects=hostchip->max_objects;
for (i=0; i<max_objects; i++) {
- obj=(struct msgobj_t *)kmalloc(sizeof(struct msgobj_t),GFP_KERNEL);
+ obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t));
hostchip->msgobj[i]=obj;
if (obj == NULL)
return -ENOMEM;
- else
- if ( add_mem_to_list(obj) )
- return -ENOMEM;
-
+
memset(obj, 0, sizeof(struct msgobj_t));
atomic_set(&obj->obj_used,0);
INIT_LIST_HEAD(&obj->obj_users);
- qends = (struct canque_ends_t *)kmalloc(sizeof(struct canque_ends_t), GFP_KERNEL);
+ init_timer(&obj->tx_timeout);
+
+ qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t));
if(qends == NULL) return -ENOMEM;
- if(add_mem_to_list(qends)) return -ENOMEM;
memset(qends, 0, sizeof(struct canque_ends_t));
obj->hostchip=hostchip;
obj->object=i+1;
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/sja1000.h"
if (sja1000_standard_mask(chip,0x0000, 0xffff))
return -ENODEV;
- if (!baudrate)
- baudrate=1000;
- if (sja1000_baud_rate(chip,1000*baudrate,chip->clock,0,75,0))
+ if (!chip->baudrate)
+ chip->baudrate=1000000;
+ if (sja1000_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
return -ENODEV;
/* Enable hardware interrupts */
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/sja1000p.h"
if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff))
return -ENODEV;
- if (!baudrate)
- baudrate=1000;
- if (sja1000p_baud_rate(chip,1000*baudrate,chip->clock,0,75,0))
+ if (!chip->baudrate)
+ chip->baudrate=1000000;
+ if (sja1000p_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
return -ENODEV;
/* Enable hardware interrupts */
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/smartcan.h"
#include "../include/i82527.h"
* Version 0.6 18 Sept 2000
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/ssv.h"
#include "../include/i82527.h"
* RESET_ADDR represents the io-address of the hardware reset register.
* NR_82527 represents the number of intel 82527 chips on the board.
* NR_SJA1000 represents the number of philips sja1000 chips on the board.
- * The flags entry can currently only be PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
*/
#define RESET_ADDR 0x02
candev->nr_82527_chips=NR_82527;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=NR_82527;
- candev->flags |= PROGRAMMABLE_IRQ;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
/* The function template_program_irq is used for hardware that uses programmable
* interrupts. If your hardware doesn't use programmable interrupts you should
- * not set the candevices_t->flags entry to PROGRAMMABLE_IRQ and leave this
+ * not set the candevices_t->flags entry to CANDEV_PROGRAMMABLE_IRQ and leave this
* function unedited. Again this function is hardware specific so there's no
* example code.
*/
* possible to load the driver with the hardware option hw=template.
*/
-#include <linux/autoconf.h>
-
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/template.h"
#include "../include/i82527.h"
* %RESET_ADDR represents the io-address of the hardware reset register.
* %NR_82527 represents the number of Intel 82527 chips on the board.
* %NR_SJA1000 represents the number of Philips sja1000 chips on the board.
- * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
* the hardware uses programmable interrupts.
* Return Value: The function always returns zero
* File: src/template.c
candev->nr_82527_chips=NR_82527;
candev->nr_sja1000_chips=NR_SJA1000;
candev->nr_all_chips=NR_82527+NR_SJA1000;
- candev->flags |= PROGRAMMABLE_IRQ;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
return 0;
}
*
* The function template_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
* leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#include <linux/delay.h>
-#include <asm/errno.h>
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
+
+long virtual_bus_latency(struct msgobj_t *obj)
+{
+ long latency;
+ latency=obj->hostchip->baudrate;
+ if(latency){
+ latency=(long)HZ*1000/latency;
+ }
+ return latency;
+}
+
+
/* * * Virtual Chip Functionality * * */
int virtual_enable_configuration(struct chip_t *chip)
return IRQ_HANDLED;
}
+
+void virtual_schedule_next(struct msgobj_t *obj)
+{
+ int cmd;
+ /* dummy lock to prevent preemption fully portable way */
+ spinlock_t dummy_lock;
+
+ /* preempt_disable() */
+ spin_lock_init(&dummy_lock);
+ spin_lock(&dummy_lock);
+
+ set_bit(OBJ_TX_REQUEST,&obj->flags);
+
+ while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
+
+ clear_bit(OBJ_TX_REQUEST,&obj->flags);
+
+ cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+ if(cmd>=0) {
+ mod_timer(&obj->tx_timeout,
+ jiffies+virtual_bus_latency(obj));
+ CANMSG("virtual: scheduled delivery\n");
+
+ } else
+ clear_bit(OBJ_TX_LOCK,&obj->flags);
+
+ if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
+ DEBUGMSG("TX looping in virtual_schedule_next\n");
+ }
+
+ /* preempt_enable(); */
+ spin_unlock(&dummy_lock);
+}
+
+
+void virtual_do_tx_timeout(unsigned long data)
+{
+ struct msgobj_t *obj=(struct msgobj_t *)data;
+
+ if(obj->tx_slot) {
+ /* Deliver message to edges */
+ canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+ /* Free transmitted slot */
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot=NULL;
+ CANMSG("virtual: delayed delivery\n");
+ }
+ clear_bit(OBJ_TX_LOCK,&obj->flags);
+
+ virtual_schedule_next(obj);
+}
+
/**
* virtual_wakeup_tx: - wakeups TX processing
* @chip: pointer to chip state structure
struct canque_slot_t *slot;
int cmd;
- /* Ensure delivery of all ready slots */
-
- while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
- if(cmd==0) {
- canque_filter_msg2edges(obj->qends, &slot->msg);
+ if(!virtual_bus_latency(obj)) {
+ /* Ensure delivery of all ready slots */
+ while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
+ if(cmd==0) {
+ canque_filter_msg2edges(obj->qends, &slot->msg);
+ CANMSG("virtual: direct delivery\n");
+ }
+ canque_free_outslot(obj->qends, qedge, slot);
}
- canque_free_outslot(obj->qends, qedge, slot);
+ } else {
+ virtual_schedule_next(obj);
}
return 0;
candev->nr_82527_chips=0;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=1;
- candev->flags |= PROGRAMMABLE_IRQ*0;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
return 0;
}
*/
int virtual_init_obj_data(struct chip_t *chip, int objnr)
{
- chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
+ struct msgobj_t *obj=chip->msgobj[objnr];
+ obj->obj_base_addr=chip->chip_base_addr;
+ obj->flags=0;
+ obj->tx_timeout.function=virtual_do_tx_timeout;
+ obj->tx_timeout.data=(unsigned long)obj;
return 0;
}
* Version lincan-0.2 9 Jul 2003
*/
-#include <linux/autoconf.h>
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
if ((ret=canque_get_inslot4id(qends, &qedge, &slot,
0, msg_buff.id, 0))<0){
DEBUGMSG("Buffer is full\n");
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
if(ret < -1)
return -EIO;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot,
0, msg_buff.id, 0);
if(ret<0) {
CC = gcc
endif
-CFLAGS = -I../include -O2
+CFLAGS = -I../include -O2 -Wall
all: default
int canmsg_flags = 0;
unsigned long canmsg_id = 5;
+int block = 10;
+int count = 0;
int can_wait_sec = 1;
+int o_sync_fl = 0;
char *can_dev_name = "/dev/can0";
printf(" -d, --device <name> name of CAN device [/dev/can0]\n");
printf(" -i, --id <num> ID of generated messages\n");
printf(" -f, --flags <num> CAN filter flags\n");
+ printf(" -s, --sync open in synchronous mode\n");
printf(" -w, --wait <num> number of seconds to wait between messages\n");
+ printf(" -b, --block <num> number of messages in block\n");
+ printf(" -c, --count <num> number of sent blocks of messages\n");
printf(" -p, --prefix <str> string prefix for output\n");
printf(" -V, --version show version\n");
printf(" -h, --help this usage screen\n");
{ "uldev", 1, 0, 'd' },
{ "id", 1, 0, 'i' },
{ "flags", 1, 0, 'f' },
+ { "sync", 0, 0, 's' },
{ "wait", 1, 0, 'w' },
+ { "block", 1, 0, 'b' },
+ { "count", 1, 0, 'c' },
{ "prefix",1, 0, 'p' },
{ "version",0,0, 'V' },
{ "help", 0, 0, 'h' },
struct canmsg_t sendmsg={0,0,5,0,8,{1,2,3,4,5,6,7,8}};
int fd, ret,i,j;
- while ((opt = getopt_long(argc, argv, "d:i:f:w:p:Vh",
+ while ((opt = getopt_long(argc, argv, "d:i:f:sw:b:c:p:Vh",
&long_opts[0], NULL)) != EOF) switch (opt) {
case 'd':
can_dev_name=optarg;
case 'f':
canmsg_flags = strtol(optarg,NULL,0);
break;
+ case 's':
+ o_sync_fl = 1;
+ break;
case 'w':
can_wait_sec = strtol(optarg,NULL,0);
break;
+ case 'b':
+ block = strtol(optarg,NULL,0);
+ break;
+ case 'c':
+ count = strtol(optarg,NULL,0);
+ break;
case 'p':
prt_prefix_in = optarg;
break;
exit(opt == 'h' ? 0 : 1);
}
- if ((fd=open(can_dev_name, O_RDWR)) < 0) {
+ if ((fd=open(can_dev_name, O_RDWR | (o_sync_fl? O_SYNC:0))) < 0) {
perror("open");
printf("Error opening %s\n", can_dev_name);
exit(1);
j=0;
while (1) {
- for(i=0;i<10;i++) {
+ for(i=0;i<block;i++) {
sendmsg.flags=canmsg_flags;
sendmsg.id=canmsg_id;
sendmsg.data[0]=i;
break;
}
}
- printf("%sSent block of 10 messages #: %u\n", prt_prefix, j);
+ printf("%sSent block of %d messages #: %u\n", prt_prefix, block, j);
j++;
usleep(1000000*can_wait_sec);
+ if(count)
+ if(!--count) break;
}
close(fd);
return 0;