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