--- /dev/null
+/* can_iortl.h - RT-Linux Posix file IO interface
+ * Linux CAN-bus device driver.
+ * RT-Linux support by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifndef _CAN_IORTL_H
+#define _CAN_IORTL_H
+
+#ifdef CAN_WITH_RTL
+
+int can_open_rtl_posix(struct rtl_file *fptr);
+
+int can_release_rtl_posix(struct rtl_file *fptr);
+
+ssize_t can_read_rtl_posix(struct rtl_file *fptr, char *buffer,
+ size_t length, loff_t *ppos);
+
+ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer,
+ size_t length, loff_t *ppos);
+
+int can_ioctl_rtl_posix(struct rtl_file *, unsigned int, unsigned long);
+
+#endif /*CAN_WITH_RTL*/
+
+#endif /*_CAN_IORTL_H*/
struct {
rtl_spinlock_t rtl_lock;
rtl_wait_t rtl_readq;
+ atomic_t rtl_readq_age;
rtl_wait_t rtl_writeq;
+ atomic_t rtl_writeq_age;
rtl_wait_t rtl_emptyq;
+ atomic_t rtl_emptyq_age;
unsigned long pend_flags;
} rtlinfo;
#endif /*CAN_WITH_RTL*/
void canqueue_kern_initialize(void);
#ifdef CAN_WITH_RTL
-/* RT-Linux specific functions */
+
+extern struct tasklet_struct canque_dead_tl; /*publication required only for RTL*/
+
+/* RT-Linux specific functions and variables */
+
+extern int canqueue_rtl_irq;
+
+extern unsigned long canqueue_rtl2lin_pend;
+
+#define CAN_RTL2LIN_PEND_DEAD_b 0
void canqueue_rtl_initialize(void);
void canqueue_rtl_done(void);
void canque_dispose_edge_rtl(struct canque_edge_t *qedge);
+int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+ int cmd, unsigned long id, int prio);
+
+int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp);
+
+int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge);
+
void canque_ends_free_rtl(struct canque_ends_t *qends);
+int canqueue_ends_init_rtl(struct canque_ends_t *qends);
+
int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync);
#else /*CAN_WITH_RTL*/
#else /*CAN_WITH_RTL*/
#define can_spinlock_t rtl_spinlock_t
-#define can_spin_irqflags_t unsigned long
+#define can_spin_irqflags_t rtl_irqstate_t
#define can_spin_lock rtl_spin_lock
#define can_spin_unlock rtl_spin_unlock
#define can_spin_lock_irqsave rtl_spin_lock_irqsave
#define can_printk rtl_printf
+/*
+ * terrible hack to test rtl_file private_data concept, ugh !!!
+ * this would result in crash on architectures, where
+ * sizeof(int) < sizeof(void *)
+ */
+#define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0)
+#define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor))
+
#endif /*CAN_WITH_RTL*/
#endif /*_CAN_SYSDEP_H*/
#define CANDEV_PROGRAMMABLE_IRQ (1<<0)
#define CANDEV_IO_RESERVED (1<<1)
+/* Next flags are specific for struct canuser_t applications connection */
+#define CANUSER_RTL_CLIENT (1<<0)
+#define CANUSER_RTL_MEM (1<<1)
+#define CANUSER_DIRECT (1<<2)
+
+
enum timing_BTR1 {
MAX_TSEG1 = 15,
MAX_TSEG2 = 7
#define CANMSG(fmt,args...) can_printk(KERN_ERR "can.o: " fmt,##args)
+extern can_spinlock_t canuser_manipulation_lock;
+
/**
* struct canhardware_t - structure representing pointers to all CAN boards
* @nr_boards: number of present boards
int max_objects; /* 1 for sja1000, 15 for i82527 */
+ can_spinlock_t chip_lock;
+
#ifdef CAN_WITH_RTL
pthread_t worker_thread;
- rtl_spinlock_t rtl_lock;
unsigned long pend_flags;
#endif /*CAN_WITH_RTL*/
};
/**
* struct canuser_t - structure holding CAN user/client state
+ * @flags: used to distinguish Linux/RT-Linux type
* @peers: for connection into list of object users
* @qends: pointer to the ends structure corresponding for this user
- * @file: pointer to open device file state structure
* @msgobj: communication object the user is connected to
* @rx_edge0: default receive queue for filter IOCTL
+ * @userinfo: stores user context specific information.
+ * The field @fileinfo.file holds pointer to open device file state structure
+ * for the Linux user-space client applications
* @magic: magic number to check consistency when pointer is retrieved
* from file private field
*/
struct canuser_t {
+ unsigned long flags;
struct list_head peers;
struct canque_ends_t *qends;
- struct file *file; /* back ptr to file */
struct msgobj_t *msgobj;
struct canque_edge_t *rx_edge0; /* simplifies IOCTL */
+ union {
+ struct {
+ struct file *file; /* back ptr to file */
+ } fileinfo;
+ #ifdef CAN_WITH_RTL
+ struct {
+ struct rtl_file *file;
+ } rtlinfo;
+ #endif /*CAN_WITH_RTL*/
+ } userinfo;
int magic;
};
lincan_cards_SOURCES = pip.c pccan.c smartcan.c nsi.c cc_can104.c \
pc_i03.c pcm3680.c aim104.c m437.c pcccan.c ssv.c \
bfadcan.c pikronisa.c virtual.c template.c
+
+lincan_rtl_SOURCES = open_rtl.c close_rtl.c read_rtl.c write_rtl.c ioctl_rtl.c
lincan_SOURCES = can_queue.c can_quekern.c can_quertl.c main.c modparms.c \
devcommon.c can_devrtl.c setup.c finish.c irq.c boardlist.c \
sja1000p.c sja1000.c i82527.c \
- open.c proc.c close.c write.c read.c \
- ioctl.c select.c fasync.c proc.c $(lincan_cards_SOURCES)
+ open.c close.c read.c write.c ioctl.c select.c fasync.c \
+ proc.c $(lincan_cards_SOURCES) $(lincan_rtl_SOURCES)
can_spin_lock_irqsave(&canque_dead_func_lock, flags);
entry=canque_dead_ends.next;
can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+ /* lock can be released there, because only one instance of canque_dead_tl
+ can run at once and all other functions add ends only to head */
while(entry!=&canque_dead_ends){
- qends=list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers);
+ qends=list_entry(entry,struct canque_ends_t,dead_peers);
entry=entry->next;
if(!list_empty(&qends->inlist))
continue;
}
+static inline void canque_dead_tasklet_schedule(void)
+{
+ #ifdef CAN_WITH_RTL
+ if(!rtl_rt_system_is_idle()){
+ set_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend);
+ rtl_global_pend_irq (canqueue_rtl_irq);
+ return;
+ }
+ #endif /*CAN_WITH_RTL*/
+
+ tasklet_schedule(&canque_dead_tl);
+}
+
void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
{
can_spin_lock_irqsave(&canque_dead_func_lock, flags);
list_add(&edge->inpeers,&canque_dead_edges);
can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
- tasklet_schedule(&canque_dead_tl);
+ canque_dead_tasklet_schedule();
}
qends->ends_flags |= CAN_ENDSF_DEAD;
list_add(&qends->dead_peers,&canque_dead_ends);
can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
- tasklet_schedule(&canque_dead_tl);
+ canque_dead_tasklet_schedule();
}
struct list_head canque_pending_edges_list;
can_spinlock_t canque_pending_edges_lock;
+unsigned long canqueue_rtl2lin_pend;
-static int canqueue_rtl_irq = 0;
+int canqueue_rtl_irq = 0;
void
canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
+ if(test_and_clear_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend))
+ tasklet_schedule(&canque_dead_tl);
+
return;
}
}
+/**
+ * canque_get_inslot4id_wait_rtl - find or wait for best outgoing edge and slot for given ID
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to allocated slot
+ * @cmd: command type for slot
+ * @id: communication ID of message to send into edge
+ * @prio: optional priority of message
+ *
+ * Same as canque_get_inslot4id(), except, that it waits for free slot
+ * in case, that queue is full. Function is specific for Linux userspace clients.
+ * Return Value: If there is no usable edge negative value is returned.
+ */
+int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+ int cmd, unsigned long id, int prio)
+{
+ rtl_irqstate_t flags;
+ int ret;
+ unsigned old_age;
+ rtl_sigset_t sigset;
+
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
+ while((ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))==-1){
+ rtl_sigemptyset(&sigset);
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age))
+ sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_writeq, &qends->endinfo.rtlinfo.rtl_lock);
+ rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(RTL_SIGINTR(&sigset))
+ return -1;
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
+ }
+
+ return ret;
+}
+
+
+/**
+ * canque_get_outslot_wait_rtl - receive or wait for ready slot for given ends
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to received slot
+ *
+ * The same as canque_test_outslot(), except it waits in the case, that there is
+ * no ready slot for given ends. Function is specific for Linux userspace clients.
+ * Return Value: Negative value informs, that there is no ready output
+ * slot for given ends. Positive value is equal to the command
+ * slot has been allocated by the input side.
+ */
+int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
+ struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+{
+ rtl_irqstate_t flags;
+ int ret;
+ unsigned old_age;
+ rtl_sigset_t sigset;
+
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
+ while((ret=canque_test_outslot(qends,qedgep,slotp))==-1){
+ rtl_sigemptyset(&sigset);
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age))
+ sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_readq, &qends->endinfo.rtlinfo.rtl_lock);
+ rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(RTL_SIGINTR(&sigset))
+ return -1;
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
+ }
+ return ret;
+}
+
+
+/**
+ * canque_sync_wait_rtl - wait for all slots processing
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Functions waits for ends transition into empty state.
+ * Return Value: Positive value indicates, that edge empty state has been reached.
+ * Negative or zero value informs about interrupted wait or other problem.
+ */
+int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+ rtl_irqstate_t flags;
+ int ret;
+ unsigned old_age;
+ rtl_sigset_t sigset;
+
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
+ while(!(ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)){
+ rtl_sigemptyset(&sigset);
+ rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age))
+ sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_emptyq, &qends->endinfo.rtlinfo.rtl_lock);
+ rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ if(RTL_SIGINTR(&sigset))
+ return -1;
+ old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
+ }
+
+ return ret;
+}
+
+
/**
* canque_fifo_init_rtl - initialize one CAN FIFO
* @fifo: pointer to the FIFO structure
return canque_fifo_init_slots(fifo);
}
+
/**
* canque_fifo_done_rtl - frees slots allocated for CAN FIFO
* @fifo: pointer to the FIFO structure
switch(what){
case CANQUEUE_NOTIFY_EMPTY:
rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
break;
case CANQUEUE_NOTIFY_SPACE:
rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
break;
case CANQUEUE_NOTIFY_PROC:
rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
break;
case CANQUEUE_NOTIFY_NOUSR:
rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
+
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
+
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
+
+ atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
+
rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
break;
case CANQUEUE_NOTIFY_DEAD_WANTED:
struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
struct canque_ends_t *qends;
struct msgobj_t *obj;
+ can_spin_irqflags_t iflags;
if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
CANMSG("can_close: bad canuser magic\n");
obj = canuser->msgobj;
qends = canuser->qends;
-
+
#ifdef CAN_ENABLE_KERN_FASYNC
can_fasync(-1, file, 0);
#endif /*CAN_ENABLE_KERN_FASYNC*/
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
list_del(&canuser->peers);
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
canuser->qends = NULL;
canqueue_ends_dispose_kern(qends, file->f_flags & O_SYNC);
kfree(canuser);
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
if(atomic_dec_and_test(&obj->obj_used)){
can_msgobj_clear_fl(obj,OPENED);
- /* FIXME: what about clearing chip HW status, stopping sending messages etc? */
};
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
MOD_DEC_USE_COUNT;
--- /dev/null
+/* close.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_malloc.h>
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+static inline
+int can_release_rtl_common(struct canuser_t *canuser, int file_flags)
+{
+ struct canque_ends_t *qends;
+ struct msgobj_t *obj;
+ can_spin_irqflags_t iflags;
+
+ obj = canuser->msgobj;
+ qends = canuser->qends;
+
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+ list_del(&canuser->peers);
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+ canuser->qends = NULL;
+ canqueue_ends_dispose_rtl(qends, file_flags & O_SYNC);
+
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+ if(atomic_dec_and_test(&obj->obj_used)){
+ can_msgobj_clear_fl(obj,OPENED);
+ };
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
+ MOD_DEC_USE_COUNT;
+ #endif
+
+ return 0;
+}
+
+
+int can_release_rtl_posix(struct rtl_file *fptr)
+{
+ struct canuser_t *canuser =
+ (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+ int ret;
+
+ if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+ CANMSG("can_release_rtl_posix: bad canuser magic\n");
+ return -ENODEV;
+ }
+
+ ret=can_release_rtl_common(canuser, fptr->f_flags);
+
+ rt_free(canuser);
+
+ return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
+
struct canque_ends_t *qends;
if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
- CANMSG("can_close: bad canuser magic\n");
+ CANMSG("can_ioctl: bad canuser magic\n");
return -ENODEV;
}
--- /dev/null
+/* ioctl.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+
+int can_ioctl_rtl_posix(struct rtl_file *fptr, unsigned int cmd, unsigned long arg)
+{
+ struct canuser_t *canuser =
+ (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+ int i=0;
+ unsigned short channel=0;
+ unsigned btr0=0, btr1=0;
+ struct msgobj_t *obj;
+ struct chip_t *chip;
+ struct canque_ends_t *qends;
+
+ if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+ CANMSG("can_ioctl_: bad canuser magic\n");
+ return -ENODEV;
+ }
+
+ obj = canuser->msgobj;
+ if (obj == NULL) {
+ CANMSG("Could not assign buffer structure\n");
+ return -1;
+ }
+
+ qends = canuser->qends;
+ chip = obj->hostchip;
+ if (chip == NULL) {
+ CANMSG("Device is not correctly configured.\n");
+ CANMSG("Please reload the driver.\n");
+ return -1;
+ }
+
+ switch (cmd) {
+ case STAT: {
+ for (i=0x0; i<0x100; i++)
+ CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i));
+ break;
+ }
+ case CMD_START: {
+ if (chip->chipspecops->start_chip(chip))
+ return -1;
+ break;
+ }
+ case CMD_STOP: {
+ if (chip->chipspecops->stop_chip(chip))
+ return -1;
+ break;
+ }
+ case CANQUE_FLUSH: {
+ canque_flush(canuser->rx_edge0);
+ break;
+ }
+ case CONF_FILTER: {
+ if(canuser->rx_edge0){
+ canque_set_filt(canuser->rx_edge0, arg, ~0, 0);
+ }
+
+ break;
+ }
+
+ case CANQUE_FILTER: {
+ struct canfilt_t canfilt;
+ copy_from_user(&canfilt, (void*)arg, sizeof(struct canfilt_t));
+ if(canuser->rx_edge0){
+ canque_set_filt(canuser->rx_edge0, canfilt.id, canfilt.mask, canfilt.flags);
+ }
+ break;
+ }
+
+ case CONF_BAUD: {
+ channel = arg & 0xff;
+ btr0 = (arg >> 8) & 0xff;
+ btr1 = (arg >> 16) & 0xff;
+
+ if (chip->chipspecops->set_btregs(chip, btr0, btr1)) {
+ CANMSG("Error setting bit timing registers\n");
+ return -1;
+ }
+ break;
+ }
+ default: {
+ CANMSG("Not a valid ioctl command\n");
+ return -EINVAL;
+ }
+
+ }
+
+ return 0;
+}
+
+#endif /*CAN_WITH_RTL*/
#include "../include/finish.h"
#include "../include/fasync.h"
+#ifdef CAN_WITH_RTL
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+#endif /*CAN_WITH_RTL*/
+
#define EXPORT_SYMTAB
+can_spinlock_t canuser_manipulation_lock;
+
/* Module parameters, some must be supplied at module loading time */
int major=CAN_MAJOR;
MODULE_PARM(major,"1i");
EXPORT_SYMBOL(can_fops);
+
+#ifdef CAN_WITH_RTL
+struct rtl_file_operations can_fops_rtl = {
+ llseek: NULL,
+ read: can_read_rtl_posix,
+ write: can_write_rtl_posix,
+ ioctl: can_ioctl_rtl_posix,
+ mmap: NULL,
+ open: can_open_rtl_posix,
+ release: can_release_rtl_posix
+};
+#endif /*CAN_WITH_RTL*/
+
+
int init_module(void)
{
int res=0,i=0, j;
#ifdef CAN_WITH_RTL
canqueue_rtl_initialize();
+ res=rtl_register_rtldev(major,DEVICE_NAME,&can_fops_rtl);
+ if (res<0) {
+ CANMSG("Error registering RT-Linux major number.\n");
+ goto rtldev_error;
+ }
#endif /*CAN_WITH_RTL*/
for (i=0; i<hardware_p->nr_boards; i++) {
canhardware_done(hardware_p);
#ifdef CAN_WITH_RTL
+ rtl_unregister_rtldev(major,DEVICE_NAME);
+ rtldev_error:
canqueue_rtl_done();
#endif /*CAN_WITH_RTL*/
canhardware_done(hardware_p);
#ifdef CAN_WITH_RTL
+ rtl_unregister_rtldev(major,DEVICE_NAME);
canqueue_rtl_done();
#endif /*CAN_WITH_RTL*/
struct canuser_t *canuser;
struct canque_ends_t *qends;
struct canque_edge_t *edge;
+ can_spin_irqflags_t iflags;
if ( ((obj=objects_p[MINOR_NR]) == NULL) ||
((chip=objects_p[MINOR_NR]->hostchip) == NULL) ) {
canuser = (struct canuser_t *)kmalloc(sizeof(struct canuser_t), GFP_KERNEL);
if(canuser == NULL) goto no_canuser;
- canuser->file = file;
+ canuser->flags=0;
+ canuser->userinfo.fileinfo.file = file;
canuser->msgobj = obj;
canuser->magic = CAN_USER_MAGIC;
file->private_data = canuser;
canqueue_ends_init_kern(qends);
canuser->qends = qends;
+ /*required to synchronize with RT-Linux context*/
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
list_add(&canuser->peers, &obj->obj_users);
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
canuser->qends, obj->qends)<0) goto no_tx_qedge;
--- /dev/null
+/* open.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_malloc.h>
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+
+static inline
+int can_open_rtl_common(struct canuser_t *canuser, int open_flags)
+{
+ struct msgobj_t *obj=canuser->msgobj;
+ struct chip_t *chip;
+ struct canque_ends_t *qends;
+ struct canque_edge_t *edge;
+ can_spin_irqflags_t iflags;
+
+ if(!obj) return -ENODEV;
+
+ can_msgobj_set_fl(obj,OPENED);
+
+ chip=obj->hostchip;
+ if (chip) {
+ if (!(chip->flags & CHIP_CONFIGURED)) {
+ if (chip->chipspecops->chip_config(chip))
+ CANMSG("Error configuring chip.\n");
+ else
+ chip->flags |= CHIP_CONFIGURED;
+
+ if (chip->chipspecops->pre_read_config(chip,obj)<0)
+ CANMSG("Error initializing chip for receiving\n");
+
+ }
+ } /* End of chip configuration */
+
+
+ qends = (struct canque_ends_t *)rt_malloc(sizeof(struct canque_ends_t));
+ if(qends == NULL) goto no_qends;
+ canqueue_ends_init_rtl(qends);
+ canuser->qends = qends;
+
+ can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+ list_add(&canuser->peers, &obj->obj_users);
+ can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+ if(canqueue_connect_edge(edge=canque_new_edge_rtl(MAX_BUF_LENGTH),
+ canuser->qends, obj->qends)<0) goto no_tx_qedge;
+
+ if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_rtl(MAX_BUF_LENGTH),
+ obj->qends, canuser->qends)<0) goto no_rx_qedge;
+ /*FIXME: more generic model should be used there*/
+ canque_edge_decref(canuser->rx_edge0);
+ canque_edge_decref(edge);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
+ MOD_INC_USE_COUNT; /*is this enough for RT-Linux context ?*/
+#endif
+
+ return 0;
+
+ no_rx_qedge:
+ canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+ canque_edge_decref(edge);
+ no_tx_qedge:
+ list_del(&canuser->peers);
+ canuser->qends = NULL;
+ canqueue_ends_dispose_kern(qends, 1);
+
+ no_qends:
+
+ return -ENOMEM;
+}
+
+
+int can_open_rtl_posix(struct rtl_file *fptr)
+{
+ int ret;
+ struct msgobj_t *obj;
+ struct chip_t *chip;
+ struct canuser_t *canuser;
+ int minor_nr = RTL_MINOR_FROM_FILEPTR(fptr);
+
+ if(minor_nr>=MAX_TOT_MSGOBJS)
+ return -ENODEV;
+
+ if ( ((obj=objects_p[minor_nr]) == NULL) ||
+ ((chip=objects_p[minor_nr]->hostchip) == NULL) ) {
+ CANMSG("There is no hardware support for the device file with minor nr.: %d\n",minor_nr);
+ return -ENODEV;
+ }
+
+ atomic_inc(&obj->obj_used);
+ DEBUGMSG("Device %d opened %d times.\n", minor_nr, atomic_read(&obj->obj_used));
+
+ canuser = (struct canuser_t *)rt_malloc(sizeof(struct canuser_t));
+ if(canuser == NULL){
+ ret=-ENOMEM;
+ goto no_canuser;
+ }
+ canuser->flags=CANUSER_RTL_CLIENT | CANUSER_RTL_MEM;
+ canuser->userinfo.rtlinfo.file = fptr;
+ canuser->msgobj = obj;
+ canuser->magic = CAN_USER_MAGIC;
+
+ /*next line would solve many problems, but RT-Linux lacks this fundamental field */
+ /*fptr->private_data = canuser;*/
+ /*to test code I am adding this terible hack*/
+ can_set_rtl_file_private_data(fptr,canuser);
+
+ ret=can_open_rtl_common(canuser, fptr->f_flags);
+ if(ret>=0) return ret;
+
+ rt_free(canuser);
+
+ no_canuser:
+ atomic_dec(&obj->obj_used);
+
+ return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
int ret=0;
if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
- CANMSG("can_close: bad canuser magic\n");
+ CANMSG("can_read: bad canuser magic\n");
return -ENODEV;
}
--- /dev/null
+/* read.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+/* This is the 'Normal' read handler for normal transmission messages */
+static inline
+ssize_t can_std_read_rtl(struct canque_ends_t *qends, int nonblock_fl,
+ char *buffer, size_t length)
+{
+ int ret;
+ struct canmsg_t *msg_buff = (struct canmsg_t *)buffer;
+ int bytes_to_copy;
+ struct canque_edge_t *qedge;
+ struct canque_slot_t *slot;
+
+ ret=canque_test_outslot(qends, &qedge, &slot);
+ if(ret<0){
+ if (nonblock_fl) {
+ return -EAGAIN;
+ }
+ ret=canque_get_outslot_wait_rtl(qends, &qedge, &slot);
+ if(ret<0){
+ if (ret==-1) {
+ DEBUGMSG("Rx interrupted\n");
+ return -EINTR;
+ }
+
+ return -EIO;
+ }
+ }
+ *(msg_buff++)=slot->msg;
+ canque_free_outslot(qends, qedge, slot);
+ bytes_to_copy = length-sizeof(struct canmsg_t);
+
+ while (bytes_to_copy > 0) {
+ ret=canque_test_outslot(qends, &qedge, &slot);
+ if(ret<0)
+ break;
+ *(msg_buff++)=slot->msg;
+ canque_free_outslot(qends, qedge, slot);
+ bytes_to_copy -= sizeof(struct canmsg_t);
+ }
+
+ return length-bytes_to_copy;
+}
+
+
+ssize_t can_read_rtl_posix(struct rtl_file *fptr, char *buffer,
+ size_t length, loff_t *ppos)
+{
+ struct canuser_t *canuser =
+ (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+ struct canque_ends_t *qends;
+ int ret;
+
+ if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+ CANMSG("can_read_rtl_posix: bad canuser magic\n");
+ return -ENODEV;
+ }
+
+ if (length < sizeof(struct canmsg_t)) {
+ DEBUGMSG("Trying to read less bytes than a CAN message, \n");
+ DEBUGMSG("this will always return zero.\n");
+ return 0;
+ }
+
+ qends = canuser->qends;
+
+ /*if (((struct canmsg_t *)buffer)->flags & MSG_RTR)
+ ret = can_rtr_read(chip, obj, buffer);
+ else*/
+ ret = can_std_read_rtl(qends, fptr->f_flags & O_NONBLOCK,
+ buffer, length);
+
+ return ret;
+}
+
+#endif /*CAN_WITH_RTL*/
+
struct canque_edge_t *qedge;
struct canque_slot_t *slot;
int ret = 0;
- int bytes_to_copy = 0;
+ unsigned bytes_to_copy;
if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
- CANMSG("can_close: bad canuser magic\n");
+ CANMSG("can_write: bad canuser magic\n");
return -ENODEV;
}
DEBUGMSG("this will always return 0 !\n");
return 0;
}
- if (length > 8 * sizeof(struct canmsg_t)) {
+ if (length > INT_MAX) {
CANMSG("Trying to write more than is supported.\n");
return -1;
}
/*
* Try to send more messages
*/
- while (bytes_to_copy > 0) {
+ while (bytes_to_copy >= sizeof(struct canmsg_t)) {
+ bytes_to_copy -= sizeof(struct canmsg_t);
/* Prepare first message */
copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
/* Automatic selection of extended format if "extended" set and ID>2047 */
slot->msg=msg_buff;
canque_put_inslot(qends, qedge, slot);
buffer += sizeof(struct canmsg_t);
- bytes_to_copy -= sizeof(struct canmsg_t);
}
if(file->f_flags & O_SYNC) {
--- /dev/null
+/* write.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2 9 Jul 2003
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+
+#include <rtl_posixio.h>
+#include "../include/can_iortl.h"
+
+ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer,
+ size_t length, loff_t *ppos)
+{
+ struct canuser_t *canuser =
+ (struct canuser_t *)can_get_rtl_file_private_data(fptr);
+ const struct canmsg_t *msg_buff = (struct canmsg_t *)buffer;
+ struct canque_ends_t *qends;
+ struct canque_edge_t *qedge;
+ struct canque_slot_t *slot;
+ int msg_flags;
+ int ret;
+ size_t bytes_to_copy;
+
+ if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+ CANMSG("can_write_rtl_posix: bad canuser magic\n");
+ return -ENODEV;
+ }
+
+ if (length < sizeof(struct canmsg_t)) {
+ DEBUGMSG("Trying to write less bytes than a CAN message,\n");
+ DEBUGMSG("this will always return 0 !\n");
+ return 0;
+ }
+ if (length > INT_MAX) {
+ CANMSG("Trying to write more than is supported.\n");
+ return -1;
+ }
+
+ qends = canuser->qends;
+
+ msg_flags=msg_buff->flags;
+ /* Automatic selection of extended format if "extended" set and ID>2047 */
+ if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT;
+
+ /* If the output buffer is full, return immediately in case O_NONBLOCK
+ * has been specified or loop until space becomes available.
+ */
+ if ((ret=canque_get_inslot4id(qends, &qedge, &slot,
+ 0, msg_buff->id, 0))<0){
+ DEBUGMSG("Buffer is full\n");
+ if(ret < -1)
+ return -EIO;
+
+ if (fptr->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret=canque_get_inslot4id_wait_rtl(qends, &qedge, &slot,
+ 0, msg_buff->id, 0);
+ if (ret == -1)
+ return -EINTR;
+
+ if(ret<0) {
+ return -EIO;
+ }
+ }
+ slot->msg=*(msg_buff++);
+ slot->msg.flags=msg_flags;
+ canque_put_inslot(qends, qedge, slot);
+ bytes_to_copy = length-sizeof(struct canmsg_t);
+
+ /*
+ * Try to send more messages
+ */
+ while (bytes_to_copy >= sizeof(struct canmsg_t)) {
+ bytes_to_copy -= sizeof(struct canmsg_t);
+ msg_flags=msg_buff->flags;
+ /* Automatic selection of extended format if "extended" set and ID>2047 */
+ if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT;
+ /* Get slot */
+ if(canque_get_inslot4id(qends, &qedge, &slot,
+ 0, msg_buff->id, 0) < 0) break;
+ slot->msg=*(msg_buff++);
+ slot->msg.flags=msg_flags;
+ canque_put_inslot(qends, qedge, slot);
+ }
+
+ if(fptr->f_flags & O_SYNC) {
+ canque_sync_wait_rtl(qends, qedge);
+ }
+ return length-bytes_to_copy;
+}
+
+#endif /*CAN_WITH_RTL*/